From f169d0494ca6564992bab54004d60c67c95d7572 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 18:02:35 +0200 Subject: [PATCH 01/86] Enhance native interop safety by introducing status validation for API calls, improving diagnostics, and ensuring resource cleanup. --- .../InfiniFrame.NativeBridge.csproj | 4 + .../LibraryImports/InfiniFrameNative.cs | 276 ++-- .../LibraryImports/InfiniFrameNativeStatus.cs | 6 + .../InfiniFrameNativeTesting.cs | 28 +- .../Native/CMakeLists.txt | 4 + .../Native/Exports.Tests.cpp | 185 +-- .../Native/Exports.cpp | 1184 ++++++----------- .../Native/Exports/ExportGuards.h | 203 +++ .../Utilities/InvokeUtility.cs | 17 + src/InfiniFrame/Window/InfiniFrameWindow.cs | 192 ++- .../Window/InfiniFrameWindowExtensions.cs | 16 +- .../InfiniFrameNativeParameterTests.cs | 35 + 12 files changed, 1168 insertions(+), 982 deletions(-) create mode 100644 src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeStatus.cs create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/ExportGuards.h diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index 0423a2968..92da674a5 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -27,6 +27,10 @@ $(NativeOutputRoot)\osx\arm64\$(Configuration) + + $(DefineConstants);InfiniFrameNativeTestExports + + diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs index e6e3732c5..ab3285974 100644 --- a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs +++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs @@ -18,226 +18,229 @@ public static partial class InfiniFrameNative { #region MARSHAL CALLS FROM Non-UI Thread to UI Thread [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Invoke", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void Invoke(IntPtr instance, Action callback); + internal static partial InfiniFrameNativeStatus Invoke(IntPtr instance, Action callback); #endregion #region Register // ReSharper disable once UnusedMethodReturnValue.Local [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_register_win32", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void RegisterWin32(IntPtr hInstance); + internal static partial InfiniFrameNativeStatus RegisterWin32(IntPtr hInstance); // ReSharper disable once UnusedMethodReturnValue.Local [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_register_mac", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void RegisterMac(); + internal static partial InfiniFrameNativeStatus RegisterMac(); #endregion #region CTOR-DTOR [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ctor", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial IntPtr Constructor([MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))] in InfiniFrameNativeParameters parameters); + internal static partial InfiniFrameNativeStatus Constructor([MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))] in InfiniFrameNativeParameters parameters, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_dtor"), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void Destructor(IntPtr instance); + internal static partial InfiniFrameNativeStatus Destructor(IntPtr instance); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_AddCustomSchemeName", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void AddCustomSchemeName(IntPtr instance, string scheme); + internal static partial InfiniFrameNativeStatus AddCustomSchemeName(IntPtr instance, string scheme); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Close", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void Close(IntPtr instance); + internal static partial InfiniFrameNativeStatus Close(IntPtr instance); #endregion #region Get [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_getHwnd_win32", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial IntPtr GetWindowHandlerWin32(IntPtr instance); + internal static partial InfiniFrameNativeStatus GetWindowHandlerWin32(IntPtr instance, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetAllMonitors", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetAllMonitors(IntPtr instance, CppGetAllMonitorsDelegate callback); + internal static partial InfiniFrameNativeStatus GetAllMonitors(IntPtr instance, CppGetAllMonitorsDelegate callback); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTransparentEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetContextMenuEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetDevToolsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFullScreen", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool fullScreen); + internal static partial InfiniFrameNativeStatus GetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool fullScreen); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetGrantBrowserPermissions", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetGrantBrowserPermissions(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool grant); + internal static partial InfiniFrameNativeStatus GetGrantBrowserPermissions(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool grant); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetUserAgent", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial IntPtr GetUserAgent(IntPtr instance); + internal static partial InfiniFrameNativeStatus GetUserAgent(IntPtr instance, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMediaAutoplayEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetMediaAutoplayEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetMediaAutoplayEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFileSystemAccessEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetFileSystemAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetFileSystemAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetWebSecurityEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetWebSecurityEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetWebSecurityEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetJavascriptClipboardAccessEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetJavascriptClipboardAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetJavascriptClipboardAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMediaStreamEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetMediaStreamEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetMediaStreamEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetSmoothScrollingEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetSmoothScrollingEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetSmoothScrollingEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetIgnoreCertificateErrorsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetIgnoreCertificateErrorsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetIgnoreCertificateErrorsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetNotificationsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetNotificationsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeStatus GetNotificationsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetPosition", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetPosition(IntPtr instance, out int x, out int y); + internal static partial InfiniFrameNativeStatus GetPosition(IntPtr instance, out int x, out int y); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetResizable", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool resizable); + internal static partial InfiniFrameNativeStatus GetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool resizable); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetScreenDpi", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial uint GetScreenDpi(IntPtr instance); + internal static partial InfiniFrameNativeStatus GetScreenDpi(IntPtr instance, out uint value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetSize(IntPtr instance, out int width, out int height); + internal static partial InfiniFrameNativeStatus GetSize(IntPtr instance, out int width, out int height); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMaxSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetMaxSize(IntPtr instance, out int maxWidth, out int maxHeight); + internal static partial InfiniFrameNativeStatus GetMaxSize(IntPtr instance, out int maxWidth, out int maxHeight); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMinSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetMinSize(IntPtr instance, out int minWidth, out int minHeight); + internal static partial InfiniFrameNativeStatus GetMinSize(IntPtr instance, out int minWidth, out int minHeight); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTitle", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial IntPtr GetTitle(IntPtr instance); + internal static partial InfiniFrameNativeStatus GetTitle(IntPtr instance, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTopmost", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool topmost); + internal static partial InfiniFrameNativeStatus GetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool topmost); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetZoom", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetZoom(IntPtr instance, out int zoom); + internal static partial InfiniFrameNativeStatus GetZoom(IntPtr instance, out int zoom); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMaximized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool maximized); + internal static partial InfiniFrameNativeStatus GetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool maximized); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMinimized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool minimized); + internal static partial InfiniFrameNativeStatus GetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool minimized); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetZoomEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool zoomEnabled); + internal static partial InfiniFrameNativeStatus GetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool zoomEnabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetIconFileName", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial IntPtr GetIconFileName(IntPtr instance); + internal static partial InfiniFrameNativeStatus GetIconFileName(IntPtr instance, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFocused", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void GetFocused(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool isFocused); + internal static partial InfiniFrameNativeStatus GetFocused(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool isFocused); #endregion #region Navigate [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_NavigateToString", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void NavigateToString(IntPtr instance, string content); + internal static partial InfiniFrameNativeStatus NavigateToString(IntPtr instance, string content); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_NavigateToUrl", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void NavigateToUrl(IntPtr instance, string url); + internal static partial InfiniFrameNativeStatus NavigateToUrl(IntPtr instance, string url); #endregion #region Set [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_setWebView2RuntimePath_win32", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetWebView2RuntimePath_win32(IntPtr instance, string webView2RuntimePath); + internal static partial InfiniFrameNativeStatus SetWebView2RuntimePath_win32(IntPtr instance, string webView2RuntimePath); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTransparentEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); + internal static partial InfiniFrameNativeStatus SetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetContextMenuEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); + internal static partial InfiniFrameNativeStatus SetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetDevToolsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); + internal static partial InfiniFrameNativeStatus SetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetFullScreen", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool fullScreen); + internal static partial InfiniFrameNativeStatus SetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool fullScreen); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMaximized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool maximized); + internal static partial InfiniFrameNativeStatus SetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool maximized); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMaxSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetMaxSize(IntPtr instance, int maxWidth, int maxHeight); + internal static partial InfiniFrameNativeStatus SetMaxSize(IntPtr instance, int maxWidth, int maxHeight); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMinimized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool minimized); + internal static partial InfiniFrameNativeStatus SetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool minimized); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMinSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetMinSize(IntPtr instance, int minWidth, int minHeight); + internal static partial InfiniFrameNativeStatus SetMinSize(IntPtr instance, int minWidth, int minHeight); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetResizable", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool resizable); + internal static partial InfiniFrameNativeStatus SetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool resizable); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetPosition", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetPosition(IntPtr instance, int x, int y); + internal static partial InfiniFrameNativeStatus SetPosition(IntPtr instance, int x, int y); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetSize(IntPtr instance, int width, int height); + internal static partial InfiniFrameNativeStatus SetSize(IntPtr instance, int width, int height); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTitle", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetTitle(IntPtr instance, string? title); + internal static partial InfiniFrameNativeStatus SetTitle(IntPtr instance, string? title); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTopmost", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool topmost); + internal static partial InfiniFrameNativeStatus SetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool topmost); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetIconFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetIconFile(IntPtr instance, string filename); + internal static partial InfiniFrameNativeStatus SetIconFile(IntPtr instance, string filename); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetZoom", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetZoom(IntPtr instance, int zoom); + internal static partial InfiniFrameNativeStatus SetZoom(IntPtr instance, int zoom); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetZoomEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool zoomEnabled); + internal static partial InfiniFrameNativeStatus SetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool zoomEnabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetFocused", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SetFocused(IntPtr instance); + internal static partial InfiniFrameNativeStatus SetFocused(IntPtr instance); #endregion #region Misc [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Center", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void Center(IntPtr instance); + internal static partial InfiniFrameNativeStatus Center(IntPtr instance); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Restore", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void Restore(IntPtr instance); + internal static partial InfiniFrameNativeStatus Restore(IntPtr instance); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ClearBrowserAutoFill", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void ClearBrowserAutoFill(IntPtr instance); + internal static partial InfiniFrameNativeStatus ClearBrowserAutoFill(IntPtr instance); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SendWebMessage", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void SendWebMessage(IntPtr instance, string message); + internal static partial InfiniFrameNativeStatus SendWebMessage(IntPtr instance, string message); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowNotification", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void ShowNotification(IntPtr instance, string title, string body); + internal static partial InfiniFrameNativeStatus ShowNotification(IntPtr instance, string title, string body); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_WaitForExit", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void WaitForExit(IntPtr instance); + internal static partial InfiniFrameNativeStatus WaitForExit(IntPtr instance); #endregion #region Dialog [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowOpenFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial IntPtr ShowOpenFile(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, string[] filters, int filtersCount, out int resultCount); + internal static partial InfiniFrameNativeStatus ShowOpenFile(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, string[] filters, int filtersCount, out int resultCount, out IntPtr values); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowOpenFolder", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial IntPtr ShowOpenFolder(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, out int resultCount); + internal static partial InfiniFrameNativeStatus ShowOpenFolder(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, out int resultCount, out IntPtr values); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowSaveFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial IntPtr ShowSaveFile(IntPtr inst, string title, string defaultPath, string[] filters, int filtersCount, string? defaultFileName); + internal static partial InfiniFrameNativeStatus ShowSaveFile(IntPtr inst, string title, string defaultPath, string[] filters, int filtersCount, string? defaultFileName, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowMessage", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameDialogResult ShowMessage(IntPtr inst, string title, string text, InfiniFrameDialogButtons buttons, InfiniFrameDialogIcon icon); + internal static partial InfiniFrameNativeStatus ShowMessage(IntPtr inst, string title, string text, InfiniFrameDialogButtons buttons, InfiniFrameDialogIcon icon, out InfiniFrameDialogResult value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_FreeString", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void FreeString(IntPtr value); + internal static partial InfiniFrameNativeStatus FreeString(IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_FreeStringArray", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial void FreeStringArray(IntPtr values, int count); + internal static partial InfiniFrameNativeStatus FreeStringArray(IntPtr values, int count); + + [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetLastErrorMessage", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + private static partial InfiniFrameNativeStatus GetLastErrorMessagePtr(out IntPtr value); #endregion #region Overloads @@ -249,59 +252,134 @@ public static partial class InfiniFrameNative { : Marshal.PtrToStringUTF8(ptr); } - internal static void GetHeight(IntPtr instance, out int height) => GetSize(instance, out _, out height); - internal static void GetWidth(IntPtr instance, out int width) => GetSize(instance, out width, out _); - internal static void GetMaxHeight(IntPtr instance, out int maxHeight) => GetMaxSize(instance, out _, out maxHeight); - internal static void GetMaxWidth(IntPtr instance, out int maxWidth) => GetMaxSize(instance, out maxWidth, out _); - internal static void GetMinHeight(IntPtr instance, out int minHeight) => GetMinSize(instance, out _, out minHeight); - internal static void GetMinWidth(IntPtr instance, out int minWidth) => GetMinSize(instance, out minWidth, out _); + internal static InfiniFrameNativeStatus GetHeight(IntPtr instance, out int height) + => GetSize(instance, out _, out height); + + internal static InfiniFrameNativeStatus GetWidth(IntPtr instance, out int width) + => GetSize(instance, out width, out _); + + internal static InfiniFrameNativeStatus GetMaxHeight(IntPtr instance, out int maxHeight) + => GetMaxSize(instance, out _, out maxHeight); + + internal static InfiniFrameNativeStatus GetMaxWidth(IntPtr instance, out int maxWidth) + => GetMaxSize(instance, out maxWidth, out _); + + internal static InfiniFrameNativeStatus GetMinHeight(IntPtr instance, out int minHeight) + => GetMinSize(instance, out _, out minHeight); - internal static void GetLeft(IntPtr instance, out int left) => GetPosition(instance, out left, out _); - internal static void GetTop(IntPtr instance, out int top) => GetPosition(instance, out _, out top); + internal static InfiniFrameNativeStatus GetMinWidth(IntPtr instance, out int minWidth) + => GetMinSize(instance, out minWidth, out _); - internal static void GetSize(IntPtr instance, out Size size) { - GetSize(instance, out int width, out int height); + internal static InfiniFrameNativeStatus GetLeft(IntPtr instance, out int left) + => GetPosition(instance, out left, out _); + + internal static InfiniFrameNativeStatus GetTop(IntPtr instance, out int top) + => GetPosition(instance, out _, out top); + + internal static InfiniFrameNativeStatus GetSize(IntPtr instance, out Size size) { + InfiniFrameNativeStatus status = GetSize(instance, out int width, out int height); size = new Size(width, height); + return status; } - internal static void GetMaxSize(IntPtr instance, out Size size) { - GetMaxSize(instance, out int width, out int height); + internal static InfiniFrameNativeStatus GetMaxSize(IntPtr instance, out Size size) { + InfiniFrameNativeStatus status = GetMaxSize(instance, out int width, out int height); size = new Size(width, height); + return status; } - internal static void GetMinSize(IntPtr instance, out Size size) { - GetMinSize(instance, out int width, out int height); + internal static InfiniFrameNativeStatus GetMinSize(IntPtr instance, out Size size) { + InfiniFrameNativeStatus status = GetMinSize(instance, out int width, out int height); size = new Size(width, height); + return status; } - internal static void GetPosition(IntPtr instance, out Point position) { - GetPosition(instance, out int left, out int top); + internal static InfiniFrameNativeStatus GetPosition(IntPtr instance, out Point position) { + InfiniFrameNativeStatus status = GetPosition(instance, out int left, out int top); position = new Point(left, top); + return status; } - internal static void GetWindowRectangle(IntPtr instance, out int x, out int y, out int width, out int height) { - GetSize(instance, out width, out height); - GetPosition(instance, out x, out y); + internal static InfiniFrameNativeStatus GetWindowRectangle(IntPtr instance, out int x, out int y, out int width, out int height) { + InfiniFrameNativeStatus sizeStatus = GetSize(instance, out width, out height); + if (sizeStatus != InfiniFrameNativeStatus.Success) { + x = 0; + y = 0; + return sizeStatus; + } + + return GetPosition(instance, out x, out y); } - internal static void GetWindowRectangle(IntPtr instance, out Rectangle rectangle) { - GetWindowRectangle(instance, out int x, out int y, out int width, out int height); + internal static InfiniFrameNativeStatus GetWindowRectangle(IntPtr instance, out Rectangle rectangle) { + InfiniFrameNativeStatus status = GetWindowRectangle(instance, out int x, out int y, out int width, out int height); rectangle = new Rectangle(x, y, width, height); + return status; } - internal static void GetUserAgent(IntPtr instance, out string? userAgent) { - IntPtr ptr = GetUserAgent(instance); - userAgent = PtrToNativeString(ptr); + internal static InfiniFrameNativeStatus GetUserAgent(IntPtr instance, out string? userAgent) { + InfiniFrameNativeStatus status = GetUserAgent(instance, out IntPtr ptr); + try { + userAgent = PtrToNativeString(ptr); + } + finally { + if (ptr != IntPtr.Zero) { + FreeString(ptr); + } + } + + return status; } - internal static void GetTitle(IntPtr instance, out string? title) { - IntPtr ptr = GetTitle(instance); - title = PtrToNativeString(ptr); + internal static InfiniFrameNativeStatus GetTitle(IntPtr instance, out string? title) { + InfiniFrameNativeStatus status = GetTitle(instance, out IntPtr ptr); + try { + title = PtrToNativeString(ptr); + } + finally { + if (ptr != IntPtr.Zero) { + FreeString(ptr); + } + } + + return status; } - internal static void GetIconFileName(IntPtr instance, out string iconFileName) { - IntPtr ptr = GetIconFileName(instance); - iconFileName = PtrToNativeString(ptr) ?? string.Empty; + internal static InfiniFrameNativeStatus GetIconFileName(IntPtr instance, out string iconFileName) { + InfiniFrameNativeStatus status = GetIconFileName(instance, out IntPtr ptr); + try { + iconFileName = PtrToNativeString(ptr) ?? string.Empty; + } + finally { + if (ptr != IntPtr.Zero) { + FreeString(ptr); + } + } + + return status; + } + + internal static string? GetLastErrorMessage() { + InfiniFrameNativeStatus status = GetLastErrorMessagePtr(out IntPtr ptr); + if (status != InfiniFrameNativeStatus.Success || ptr == IntPtr.Zero) return null; + + try { + return PtrToNativeString(ptr); + } + finally { + FreeString(ptr); + } + } + + internal static InfiniFrameNativeStatus EnsureSucceeded(InfiniFrameNativeStatus status, string operationName) { + + int fallbackLastError = Marshal.GetLastPInvokeError(); + + if (status is InfiniFrameNativeStatus.Success && fallbackLastError is 0) return status; + + + string fallbackMessage = GetLastErrorMessage() ?? "No native error message provided."; + throw new ApplicationException($"Native interop call '{operationName}' failed with unknown status state. Fallback last error {fallbackLastError}. {fallbackMessage}"); } #endregion } diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeStatus.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeStatus.cs new file mode 100644 index 000000000..6ff79abec --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeStatus.cs @@ -0,0 +1,6 @@ +namespace InfiniFrame.NativeBridge; +internal enum InfiniFrameNativeStatus { + Success = 0, + InvalidArgument = 22, + OperationFailed = 14 +} diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs index 1eb408204..b0bece63c 100644 --- a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs +++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs @@ -12,22 +12,25 @@ namespace InfiniFrame.NativeBridge; // Code // --------------------------------------------------------------------------------------------------------------------- public static partial class InfiniFrameNativeTesting { - [LibraryImport(NativeLibraryName, EntryPoint = "InfiniWindowTests_NativeParametersReturnAsIs", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - private static partial void NativeParametersReturnAsIsNative( +#if InfiniFrameNativeTestExports + [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrameNativeTests_NativeParametersReturnAsIs", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + private static partial InfiniFrameNativeStatus NativeParametersReturnAsIsNative( [MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))] in InfiniFrameNativeParameters parameters, out IntPtr newParameters ); - [LibraryImport(NativeLibraryName, EntryPoint = "InfiniWindowTests_FreeInitParams", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - private static partial void FreeInitParamsNative(IntPtr parameters); + [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrameNativeTests_FreeInitParams", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + private static partial InfiniFrameNativeStatus FreeInitParamsNative(IntPtr parameters); /// /// Returns a native pointer to a newly allocated InfiniFrameInitParams clone. /// Ownership is transferred to managed caller, which must call exactly once. /// internal static IntPtr NativeParametersReturnAsIsPtr(ref InfiniFrameNativeParameters parameters) { - NativeParametersReturnAsIsNative(in parameters, out IntPtr newParametersPtr); + InfiniFrameNative.EnsureSucceeded( + NativeParametersReturnAsIsNative(in parameters, out IntPtr newParametersPtr), + nameof(NativeParametersReturnAsIsNative)); // ReSharper disable once ConvertIfStatementToReturnStatement if (newParametersPtr == IntPtr.Zero) throw new InvalidOperationException("Native function returned null pointer"); @@ -38,6 +41,19 @@ internal static IntPtr NativeParametersReturnAsIsPtr(ref InfiniFrameNativeParame internal static void FreeInitParams(IntPtr newParametersPtr) { if (newParametersPtr == IntPtr.Zero) return; - FreeInitParamsNative(newParametersPtr); + InfiniFrameNative.EnsureSucceeded( + FreeInitParamsNative(newParametersPtr), + nameof(FreeInitParamsNative)); } +#else + internal static IntPtr NativeParametersReturnAsIsPtr(ref InfiniFrameNativeParameters parameters) { + throw new PlatformNotSupportedException("InfiniFrame native test exports are not enabled for this build."); + } + + internal static void FreeInitParams(IntPtr newParametersPtr) { + if (newParametersPtr != IntPtr.Zero) { + throw new PlatformNotSupportedException("InfiniFrame native test exports are not enabled for this build."); + } + } +#endif } diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index bf0790ce3..441980030 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -113,6 +113,10 @@ elseif (UNIX) infiniframe_setup_embed_js(${PROJECT_NAME}) endif () +target_compile_definitions(${PROJECT_NAME} PRIVATE + $<$:INFINIFRAME_BUILD_TEST_EXPORTS=1> +) + # ---------------------------------------------------------------------------------------------------------------------- # Sanitizers (Debug only) # ---------------------------------------------------------------------------------------------------------------------- diff --git a/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp index 16bad74a7..ce29df950 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp @@ -1,4 +1,5 @@ -#include "Core/InfiniFrame.h" +#include "Core/InfiniFrame.h" +#include "Exports/ExportGuards.h" #ifdef _WIN32 #define EXPORTED __declspec(dllexport) @@ -6,109 +7,127 @@ #define EXPORTED #endif +#if defined(INFINIFRAME_BUILD_TEST_EXPORTS) + +using infiniframe::exports::EnsureNotNull; +using infiniframe::exports::RunExportStatus; + #ifdef _WIN32 inline AutoString duplicateString(const AutoStringConst str) { - if (str == nullptr) + if (str == nullptr) { return nullptr; + } + const size_t len = wcslen(str); auto* copy = new wchar_t[len + 1]; wcscpy_s(copy, len + 1, str); return copy; } #else -inline AutoString duplicateString(AutoStringConst str) { - if (str == nullptr) +inline AutoString duplicateString(const AutoStringConst str) { + if (str == nullptr) { return nullptr; + } + const size_t len = strlen(str); - auto copy = new char[len + 1]; + auto* copy = new char[len + 1]; strcpy(copy, str); return copy; } #endif extern "C" { - EXPORTED void InfiniWindowTests_NativeParametersReturnAsIs( + EXPORTED InteropStatus InfiniFrameNativeTests_NativeParametersReturnAsIs( const InfiniFrameInitParams* params, InfiniFrameInitParams** new_params ) { - *new_params = new InfiniFrameInitParams(); - - // Deep copy AutoString fields - (*new_params)->StartString = duplicateString(params->StartString); - (*new_params)->StartUrl = duplicateString(params->StartUrl); - (*new_params)->Title = duplicateString(params->Title); - (*new_params)->WindowIconFile = duplicateString(params->WindowIconFile); - (*new_params)->TemporaryFilesPath = duplicateString(params->TemporaryFilesPath); - (*new_params)->UserAgent = duplicateString(params->UserAgent); - (*new_params)->BrowserControlInitParameters = duplicateString(params->BrowserControlInitParameters); - (*new_params)->NotificationRegistrationId = duplicateString(params->NotificationRegistrationId); - - // Copy the rest using memcpy (copy everything except the strings we already handled) - (*new_params)->ParentInstance = params->ParentInstance; - (*new_params)->ClosingHandler = params->ClosingHandler; - (*new_params)->ClosedHandler = params->ClosedHandler; - (*new_params)->FocusInHandler = params->FocusInHandler; - (*new_params)->FocusOutHandler = params->FocusOutHandler; - (*new_params)->ResizedHandler = params->ResizedHandler; - (*new_params)->MaximizedHandler = params->MaximizedHandler; - (*new_params)->RestoredHandler = params->RestoredHandler; - (*new_params)->MinimizedHandler = params->MinimizedHandler; - (*new_params)->MovedHandler = params->MovedHandler; - (*new_params)->WebMessageReceivedHandler = params->WebMessageReceivedHandler; - (*new_params)->CustomSchemeHandler = params->CustomSchemeHandler; - - // Copy array - memcpy((*new_params)->CustomSchemeNames, params->CustomSchemeNames, sizeof(params->CustomSchemeNames)); - - // Copy all numeric and bool fields in one go - (*new_params)->Left = params->Left; - (*new_params)->Top = params->Top; - (*new_params)->Width = params->Width; - (*new_params)->Height = params->Height; - (*new_params)->Zoom = params->Zoom; - (*new_params)->MinWidth = params->MinWidth; - (*new_params)->MinHeight = params->MinHeight; - (*new_params)->MaxWidth = params->MaxWidth; - (*new_params)->MaxHeight = params->MaxHeight; - (*new_params)->CenterOnInitialize = params->CenterOnInitialize; - (*new_params)->Chromeless = params->Chromeless; - (*new_params)->Transparent = params->Transparent; - (*new_params)->ContextMenuEnabled = params->ContextMenuEnabled; - (*new_params)->ZoomEnabled = params->ZoomEnabled; - (*new_params)->DevToolsEnabled = params->DevToolsEnabled; - (*new_params)->FullScreen = params->FullScreen; - (*new_params)->Maximized = params->Maximized; - (*new_params)->Minimized = params->Minimized; - (*new_params)->Resizable = params->Resizable; - (*new_params)->Topmost = params->Topmost; - (*new_params)->UseOsDefaultLocation = params->UseOsDefaultLocation; - (*new_params)->UseOsDefaultSize = params->UseOsDefaultSize; - (*new_params)->GrantBrowserPermissions = params->GrantBrowserPermissions; - (*new_params)->MediaAutoplayEnabled = params->MediaAutoplayEnabled; - (*new_params)->FileSystemAccessEnabled = params->FileSystemAccessEnabled; - (*new_params)->WebSecurityEnabled = params->WebSecurityEnabled; - (*new_params)->JavascriptClipboardAccessEnabled = params->JavascriptClipboardAccessEnabled; - (*new_params)->MediaStreamEnabled = params->MediaStreamEnabled; - (*new_params)->SmoothScrollingEnabled = params->SmoothScrollingEnabled; - (*new_params)->IgnoreCertificateErrorsEnabled = params->IgnoreCertificateErrorsEnabled; - (*new_params)->NotificationsEnabled = params->NotificationsEnabled; - (*new_params)->Size = params->Size; + if (new_params != nullptr) { + *new_params = nullptr; + } + + return RunExportStatus([&] { + if (!EnsureNotNull(params, "params") || !EnsureNotNull(new_params, "new_params")) { + throw std::invalid_argument("Test export argument is null."); + } + + *new_params = new InfiniFrameInitParams(); + + (*new_params)->StartString = duplicateString(params->StartString); + (*new_params)->StartUrl = duplicateString(params->StartUrl); + (*new_params)->Title = duplicateString(params->Title); + (*new_params)->WindowIconFile = duplicateString(params->WindowIconFile); + (*new_params)->TemporaryFilesPath = duplicateString(params->TemporaryFilesPath); + (*new_params)->UserAgent = duplicateString(params->UserAgent); + (*new_params)->BrowserControlInitParameters = duplicateString(params->BrowserControlInitParameters); + (*new_params)->NotificationRegistrationId = duplicateString(params->NotificationRegistrationId); + + (*new_params)->ParentInstance = params->ParentInstance; + (*new_params)->ClosingHandler = params->ClosingHandler; + (*new_params)->ClosedHandler = params->ClosedHandler; + (*new_params)->FocusInHandler = params->FocusInHandler; + (*new_params)->FocusOutHandler = params->FocusOutHandler; + (*new_params)->ResizedHandler = params->ResizedHandler; + (*new_params)->MaximizedHandler = params->MaximizedHandler; + (*new_params)->RestoredHandler = params->RestoredHandler; + (*new_params)->MinimizedHandler = params->MinimizedHandler; + (*new_params)->MovedHandler = params->MovedHandler; + (*new_params)->WebMessageReceivedHandler = params->WebMessageReceivedHandler; + (*new_params)->CustomSchemeHandler = params->CustomSchemeHandler; + memcpy((*new_params)->CustomSchemeNames, params->CustomSchemeNames, sizeof(params->CustomSchemeNames)); + + (*new_params)->Left = params->Left; + (*new_params)->Top = params->Top; + (*new_params)->Width = params->Width; + (*new_params)->Height = params->Height; + (*new_params)->Zoom = params->Zoom; + (*new_params)->MinWidth = params->MinWidth; + (*new_params)->MinHeight = params->MinHeight; + (*new_params)->MaxWidth = params->MaxWidth; + (*new_params)->MaxHeight = params->MaxHeight; + (*new_params)->CenterOnInitialize = params->CenterOnInitialize; + (*new_params)->Chromeless = params->Chromeless; + (*new_params)->Transparent = params->Transparent; + (*new_params)->ContextMenuEnabled = params->ContextMenuEnabled; + (*new_params)->ZoomEnabled = params->ZoomEnabled; + (*new_params)->DevToolsEnabled = params->DevToolsEnabled; + (*new_params)->FullScreen = params->FullScreen; + (*new_params)->Maximized = params->Maximized; + (*new_params)->Minimized = params->Minimized; + (*new_params)->Resizable = params->Resizable; + (*new_params)->Topmost = params->Topmost; + (*new_params)->UseOsDefaultLocation = params->UseOsDefaultLocation; + (*new_params)->UseOsDefaultSize = params->UseOsDefaultSize; + (*new_params)->GrantBrowserPermissions = params->GrantBrowserPermissions; + (*new_params)->MediaAutoplayEnabled = params->MediaAutoplayEnabled; + (*new_params)->FileSystemAccessEnabled = params->FileSystemAccessEnabled; + (*new_params)->WebSecurityEnabled = params->WebSecurityEnabled; + (*new_params)->JavascriptClipboardAccessEnabled = params->JavascriptClipboardAccessEnabled; + (*new_params)->MediaStreamEnabled = params->MediaStreamEnabled; + (*new_params)->SmoothScrollingEnabled = params->SmoothScrollingEnabled; + (*new_params)->IgnoreCertificateErrorsEnabled = params->IgnoreCertificateErrorsEnabled; + (*new_params)->NotificationsEnabled = params->NotificationsEnabled; + (*new_params)->Size = params->Size; + }); } - EXPORTED void InfiniWindowTests_FreeInitParams(InfiniFrameInitParams* params) { - if (params == nullptr) - return; - - // Free only string fields that this test export duplicated. - delete[] params->StartString; - delete[] params->StartUrl; - delete[] params->Title; - delete[] params->WindowIconFile; - delete[] params->TemporaryFilesPath; - delete[] params->UserAgent; - delete[] params->BrowserControlInitParameters; - delete[] params->NotificationRegistrationId; - - delete params; + EXPORTED InteropStatus InfiniFrameNativeTests_FreeInitParams(InfiniFrameInitParams* params) { + return RunExportStatus([&] { + if (!EnsureNotNull(params, "params")) { + throw std::invalid_argument("Argument 'params' is null."); + } + + delete[] params->StartString; + delete[] params->StartUrl; + delete[] params->Title; + delete[] params->WindowIconFile; + delete[] params->TemporaryFilesPath; + delete[] params->UserAgent; + delete[] params->BrowserControlInitParameters; + delete[] params->NotificationRegistrationId; + + delete params; + }); } } + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Exports.cpp b/src/InfiniFrame.NativeBridge/Native/Exports.cpp index a463e6ccc..1badb848e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports.cpp @@ -1,4 +1,6 @@ #include "Core/InfiniFrame.h" +#include "Exports/ExportGuards.h" + #ifdef __linux__ #include #endif @@ -9,766 +11,460 @@ #define EXPORTED #endif -/** - * @file Exports.cpp - * @brief C API for InfiniFrame native interop - * - * Memory management: - * - InfiniFrame_ctor returns ownership to caller (.NET side) - * - InfiniFrame_dtor transfers ownership back and destroys instance - * - All string returns (AutoString) must be freed with InfiniFrame_FreeString - * - * Thread safety: - * - All methods except Invoke must be called from UI thread - * - Invoke marshals calls to UI thread safely - */ +using infiniframe::exports::EnsureNotNull; +using infiniframe::exports::GetLastErrorMessageCopy; +using infiniframe::exports::ResetOut; +using infiniframe::exports::ResetOut2; +using infiniframe::exports::RunExportStatus; +using infiniframe::exports::RunReturnExport; +using infiniframe::exports::RunWindowExportStatus; +using infiniframe::exports::RunWindowReturnExport; extern "C" { #ifdef _WIN32 - /** - * @brief Register InfiniFrame window class (Windows) - * @param hInstance Application instance handle - */ - EXPORTED void InfiniFrame_register_win32(const HINSTANCE hInstance) { - InfiniFrameWindow::Register(hInstance); - } - - /** - * @brief Get native window handle (Windows) - * @param instance InfiniFrame instance - * @return HWND window handle - */ - EXPORTED HWND InfiniFrame_getHwnd_win32(InfiniFrameWindow* instance) { - return instance->getHwnd(); - } - - /** - * @brief Set WebView2 runtime path (Windows) - * @param instance InfiniFrame instance - * @param webView2RuntimePath Path to WebView2 runtime - */ - EXPORTED void InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindow*, const AutoString webView2RuntimePath) { - InfiniFrameWindow::SetWebView2RuntimePath(webView2RuntimePath); - } - - /** - * @brief Get notifications enabled status (Windows) - * @param instance InfiniFrame instance - * @param disabled Output: notifications disabled status - */ - EXPORTED void InfiniFrame_GetNotificationsEnabled(InfiniFrameWindow* instance, bool* disabled) { - instance->GetNotificationsEnabled(disabled); + EXPORTED InteropStatus InfiniFrame_register_win32(const HINSTANCE hInstance) { + return RunExportStatus([&] { + if (hInstance == nullptr) throw std::invalid_argument("Argument 'hInstance' is null."); + InfiniFrameWindow::Register(hInstance); + }); + } + + EXPORTED InteropStatus InfiniFrame_getHwnd_win32(InfiniFrameWindow* instance, HWND* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->getHwnd(); + }); + } + + EXPORTED InteropStatus InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindow*, const AutoString webView2RuntimePath) { + return RunExportStatus([&] { + if (!EnsureNotNull(webView2RuntimePath, "webView2RuntimePath")) throw std::invalid_argument("Argument 'webView2RuntimePath' is null."); + InfiniFrameWindow::SetWebView2RuntimePath(webView2RuntimePath); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetNotificationsEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetNotificationsEnabled(enabled); + }); } #elif __APPLE__ - /** - * @brief Register InfiniFrame application (macOS) - */ - EXPORTED void InfiniFrame_register_mac() { - InfiniFrameWindow::Register(); + EXPORTED InteropStatus InfiniFrame_register_mac() { + return RunExportStatus([] { InfiniFrameWindow::Register(); }); } #endif - /** - * @brief Create new InfiniFrame window instance - * @param initParams Initialization parameters - * @return Raw pointer - ownership transferred to caller (.NET) - */ - EXPORTED InfiniFrameWindow* InfiniFrame_ctor(InfiniFrameInitParams* initParams) { - auto instance = std::make_unique(initParams); - return instance.release(); - } - - /** - * @brief Destroy InfiniFrame window instance - * @param instance Raw pointer from InfiniFrame_ctor - */ - EXPORTED void InfiniFrame_dtor(InfiniFrameWindow* instance) { - if (instance != nullptr) { + EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { + ResetOut(value, static_cast(nullptr)); + return RunExportStatus([&] { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (initParams == nullptr) throw std::invalid_argument("Argument 'initParams' is null."); + if (initParams->Size != static_cast(sizeof(InfiniFrameInitParams))) { + throw std::invalid_argument("InfiniFrameInitParams.Size does not match native struct size."); + } + auto instance = std::make_unique(initParams); + *value = instance.release(); + }); + } + + EXPORTED InteropStatus InfiniFrame_dtor(InfiniFrameWindow* instance) { + return RunExportStatus([&] { + if (!EnsureNotNull(instance, "instance")) throw std::invalid_argument("Argument 'instance' is null."); std::unique_ptr guard{instance}; - } - } - - /** - * @brief Center window on screen - * @param instance InfiniFrame instance - */ - EXPORTED void InfiniFrame_Center(InfiniFrameWindow* instance) { - instance->Center(); - } - - /** - * @brief Clear browser auto-fill data - * @param instance InfiniFrame instance - */ - EXPORTED void InfiniFrame_ClearBrowserAutoFill(InfiniFrameWindow* instance) { - instance->ClearBrowserAutoFill(); - } - - /** - * @brief Close window - * @param instance InfiniFrame instance - */ - EXPORTED void InfiniFrame_Close(InfiniFrameWindow* instance) { - instance->Close(); - } - - /** - * @brief Get transparent enabled status - * @param instance InfiniFrame instance - * @param enabled Output: transparent enabled status - */ - EXPORTED void InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetTransparentEnabled(enabled); - } - - /** - * @brief Get context menu enabled status - * @param instance InfiniFrame instance - * @param enabled Output: context menu enabled status - */ - EXPORTED void InfiniFrame_GetContextMenuEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetContextMenuEnabled(enabled); - } - - /** - * @brief Get zoom enabled status - * @param instance InfiniFrame instance - * @param enabled Output: zoom enabled status - */ - EXPORTED void InfiniFrame_GetZoomEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetZoomEnabled(enabled); - } - - /** - * @brief Get dev tools enabled status - * @param instance InfiniFrame instance - * @param enabled Output: dev tools enabled status - */ - EXPORTED void InfiniFrame_GetDevToolsEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetDevToolsEnabled(enabled); - } - - /** - * @brief Get full screen status - * @param instance InfiniFrame instance - * @param fullScreen Output: full screen status - */ - EXPORTED void InfiniFrame_GetFullScreen(InfiniFrameWindow* instance, bool* fullScreen) { - instance->GetFullScreen(fullScreen); - } - - /** - * @brief Get grant browser permissions status - * @param instance InfiniFrame instance - * @param grant Output: grant browser permissions status - */ - EXPORTED void InfiniFrame_GetGrantBrowserPermissions(InfiniFrameWindow* instance, bool* grant) { - instance->GetGrantBrowserPermissions(grant); - } - - /** - * @brief Get user agent string - * @param instance InfiniFrame instance - * @return User agent string - */ - EXPORTED AutoString InfiniFrame_GetUserAgent(InfiniFrameWindow* instance) { - return instance->GetUserAgent(); - } - - /** - * @brief Get media autoplay enabled status - * @param instance InfiniFrame instance - * @param enabled Output: media autoplay enabled status - */ - EXPORTED void InfiniFrame_GetMediaAutoplayEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetMediaAutoplayEnabled(enabled); - } - - /** - * @brief Get file system access enabled status - * @param instance InfiniFrame instance - * @param enabled Output: file system access enabled status - */ - EXPORTED void InfiniFrame_GetFileSystemAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetFileSystemAccessEnabled(enabled); - } - - /** - * @brief Get web security enabled status - * @param instance InfiniFrame instance - * @param enabled Output: web security enabled status - */ - EXPORTED void InfiniFrame_GetWebSecurityEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetWebSecurityEnabled(enabled); - } - - /** - * @brief Get JavaScript clipboard access enabled status - * @param instance InfiniFrame instance - * @param enabled Output: JavaScript clipboard access enabled status - */ - EXPORTED void InfiniFrame_GetJavascriptClipboardAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetJavascriptClipboardAccessEnabled(enabled); - } - - /** - * @brief Get media stream enabled status - * @param instance InfiniFrame instance - * @param enabled Output: media stream enabled status - */ - EXPORTED void InfiniFrame_GetMediaStreamEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetMediaStreamEnabled(enabled); - } - - /** - * @brief Get smooth scrolling enabled status - * @param instance InfiniFrame instance - * @param enabled Output: smooth scrolling enabled status - */ - EXPORTED void InfiniFrame_GetSmoothScrollingEnabled(InfiniFrameWindow* instance, bool* enabled) { - instance->GetSmoothScrollingEnabled(enabled); - } - - /** - * @brief Get maximized status - * @param instance InfiniFrame instance - * @param isMaximized Output: maximized status - */ - EXPORTED void InfiniFrame_GetMaximized(InfiniFrameWindow* instance, bool* isMaximized) { - instance->GetMaximized(isMaximized); - } - - /** - * @brief Get minimized status - * @param instance InfiniFrame instance - * @param isMinimized Output: minimized status - */ - EXPORTED void InfiniFrame_GetMinimized(InfiniFrameWindow* instance, bool* isMinimized) { - instance->GetMinimized(isMinimized); - } - - /** - * @brief Get ignore certificate errors enabled status - * @param instance InfiniFrame instance - * @param disabled Output: ignore certificate errors enabled status - */ - EXPORTED void InfiniFrame_GetIgnoreCertificateErrorsEnabled(InfiniFrameWindow* instance, bool* disabled) { - instance->GetIgnoreCertificateErrorsEnabled(disabled); - } - - /** - * @brief Get window position - * @param instance InfiniFrame instance - * @param x Output: X coordinate - * @param y Output: Y coordinate - */ - EXPORTED void InfiniFrame_GetPosition(InfiniFrameWindow* instance, int* x, int* y) { - instance->GetPosition(x, y); - } - - /** - * @brief Get resizable status - * @param instance InfiniFrame instance - * @param resizable Output: resizable status - */ - EXPORTED void InfiniFrame_GetResizable(InfiniFrameWindow* instance, bool* resizable) { - instance->GetResizable(resizable); - } - - /** - * @brief Get screen DPI - * @param instance InfiniFrame instance - * @return Screen DPI value - */ - EXPORTED unsigned int InfiniFrame_GetScreenDpi(InfiniFrameWindow* instance) { - return instance->GetScreenDpi(); - } - - /** - * @brief Get window size - * @param instance InfiniFrame instance - * @param width Output: window width - * @param height Output: window height - */ - EXPORTED void InfiniFrame_GetSize(InfiniFrameWindow* instance, int* width, int* height) { - instance->GetSize(width, height); - } - - /** - * @brief Get the window maximum size constraints - * @param instance InfiniFrame instance - * @param width Output: maximum window width - * @param height Output: maximum window height - */ - EXPORTED void InfiniFrame_GetMaxSize(InfiniFrameWindow* instance, int* width, int* height) { - instance->GetMaxSize(width, height); - } - - /** - * @brief Get the window minimum size constraints - * @param instance InfiniFrame instance - * @param width Output: minimum window width - * @param height Output: minimum window height - */ - EXPORTED void InfiniFrame_GetMinSize(InfiniFrameWindow* instance, int* width, int* height) { - instance->GetMinSize(width, height); - } - - /** - * @brief Get window title - * @param instance InfiniFrame instance - * @return Window title string - */ - EXPORTED AutoString InfiniFrame_GetTitle(InfiniFrameWindow* instance) { - return instance->GetTitle(); - } - - /** - * @brief Get topmost status - * @param instance InfiniFrame instance - * @param topmost Output: topmost status - */ - EXPORTED void InfiniFrame_GetTopmost(InfiniFrameWindow* instance, bool* topmost) { - instance->GetTopmost(topmost); - } - - /** - * @brief Get zoom level - * @param instance InfiniFrame instance - * @param zoom Output: zoom level percentage - */ - EXPORTED void InfiniFrame_GetZoom(InfiniFrameWindow* instance, int* zoom) { - instance->GetZoom(zoom); - } - - /** - * @brief Get focused status - * @param instance InfiniFrame instance - * @param isFocused Output: focused status - */ - EXPORTED void InfiniFrame_GetFocused(InfiniFrameWindow* instance, bool* isFocused) { - instance->GetFocused(isFocused); - } - - /** - * @brief Get icon file name - * @param instance InfiniFrame instance - * @return Icon file name string - */ - EXPORTED AutoString InfiniFrame_GetIconFileName(InfiniFrameWindow* instance) { - return instance->GetIconFileName(); - } - - /** - * @brief Navigate to HTML string - * @param instance InfiniFrame instance - * @param content HTML content string - */ - EXPORTED void InfiniFrame_NavigateToString(InfiniFrameWindow* instance, const AutoString content) { - instance->NavigateToString(content); - } - - /** - * @brief Navigate to URL - * @param instance InfiniFrame instance - * @param url URL to navigate to - */ - EXPORTED void InfiniFrame_NavigateToUrl(InfiniFrameWindow* instance, const AutoString url) { - instance->NavigateToUrl(url); - } - - /** - * @brief Restore window from minimized/maximized state - * @param instance InfiniFrame instance - */ - EXPORTED void InfiniFrame_Restore(InfiniFrameWindow* instance) { - instance->Restore(); - } - - /** - * @brief Send message to WebView JavaScript - * @param instance InfiniFrame instance - * @param message Message string to send - */ - EXPORTED void InfiniFrame_SendWebMessage(InfiniFrameWindow* instance, const AutoString message) { - instance->SendWebMessage(message); - } - - /** - * @brief Set transparent enabled status - * @param instance InfiniFrame instance - * @param enabled Transparent enabled status - */ - EXPORTED void InfiniFrame_SetTransparentEnabled(InfiniFrameWindow* instance, const bool enabled) { - instance->SetTransparentEnabled(enabled); - } - - /** - * @brief Set context menu enabled status - * @param instance InfiniFrame instance - * @param enabled Context menu enabled status - */ - EXPORTED void InfiniFrame_SetContextMenuEnabled(InfiniFrameWindow* instance, const bool enabled) { - instance->SetContextMenuEnabled(enabled); - } - - /** - * @brief Set zoom enabled status - * @param instance InfiniFrame instance - * @param enabled Zoom enabled status - */ - EXPORTED void InfiniFrame_SetZoomEnabled(InfiniFrameWindow* instance, const bool enabled) { - instance->SetZoomEnabled(enabled); - } - - /** - * @brief Set dev tools enabled status - * @param instance InfiniFrame instance - * @param enabled Dev tools enabled status - */ - EXPORTED void InfiniFrame_SetDevToolsEnabled(InfiniFrameWindow* instance, const bool enabled) { - instance->SetDevToolsEnabled(enabled); - } - - /** - * @brief Set full screen status - * @param instance InfiniFrame instance - * @param fullScreen Full screen status - */ - EXPORTED void InfiniFrame_SetFullScreen(InfiniFrameWindow* instance, const bool fullScreen) { - instance->SetFullScreen(fullScreen); - } - - /** - * @brief Set window icon from file - * @param instance InfiniFrame instance - * @param filename Icon file path - */ - EXPORTED void InfiniFrame_SetIconFile(InfiniFrameWindow* instance, const AutoString filename) { - instance->SetIconFile(filename); - } - - /** - * @brief Set maximized status - * @param instance InfiniFrame instance - * @param maximized Maximized status - */ - EXPORTED void InfiniFrame_SetMaximized(InfiniFrameWindow* instance, const bool maximized) { - instance->SetMaximized(maximized); - } - - /** - * @brief Set maximum window size - * @param instance InfiniFrame instance - * @param width Maximum width - * @param height Maximum height - */ - EXPORTED void InfiniFrame_SetMaxSize(InfiniFrameWindow* instance, const int width, const int height) { - instance->SetMaxSize(width, height); - } - - /** - * @brief Set minimized status - * @param instance InfiniFrame instance - * @param minimized Minimized status - */ - EXPORTED void InfiniFrame_SetMinimized(InfiniFrameWindow* instance, const bool minimized) { - instance->SetMinimized(minimized); - } - - /** - * @brief Set minimum window size - * @param instance InfiniFrame instance - * @param width Minimum width - * @param height Minimum height - */ - EXPORTED void InfiniFrame_SetMinSize(InfiniFrameWindow* instance, const int width, const int height) { - instance->SetMinSize(width, height); - } - - /** - * @brief Set window position - * @param instance InfiniFrame instance - * @param x X coordinate - * @param y Y coordinate - */ - EXPORTED void InfiniFrame_SetPosition(InfiniFrameWindow* instance, const int x, const int y) { - instance->SetPosition(x, y); - } - - /** - * @brief Set resizable status - * @param instance InfiniFrame instance - * @param resizable Resizable status - */ - EXPORTED void InfiniFrame_SetResizable(InfiniFrameWindow* instance, const bool resizable) { - instance->SetResizable(resizable); - } - - /** - * @brief Set window size - * @param instance InfiniFrame instance - * @param width Window width - * @param height Window height - */ - EXPORTED void InfiniFrame_SetSize(InfiniFrameWindow* instance, const int width, const int height) { - instance->SetSize(width, height); - } - - /** - * @brief Set window title - * @param instance InfiniFrame instance - * @param title Window title string - */ - EXPORTED void InfiniFrame_SetTitle(InfiniFrameWindow* instance, const AutoString title) { - instance->SetTitle(title); - } - - /** - * @brief Set topmost status - * @param instance InfiniFrame instance - * @param topmost Topmost status - */ - EXPORTED void InfiniFrame_SetTopmost(InfiniFrameWindow* instance, const bool topmost) { - instance->SetTopmost(topmost); - } - - /** - * @brief Set zoom level - * @param instance InfiniFrame instance - * @param zoom Zoom level percentage - */ - EXPORTED void InfiniFrame_SetZoom(InfiniFrameWindow* instance, const int zoom) { - instance->SetZoom(zoom); - } - - /** - * @brief Show notification - * @param instance InfiniFrame instance - * @param title Notification title - * @param body Notification body - */ - EXPORTED void InfiniFrame_ShowNotification( - InfiniFrameWindow* instance, - const AutoString title, - const AutoString body - ) { - instance->ShowNotification(title, body); - } - - /** - * @brief Wait for window exit - * @param instance InfiniFrame instance - */ - EXPORTED void InfiniFrame_WaitForExit(InfiniFrameWindow* instance) { - instance->WaitForExit(); - } - - /** - * @brief Free string allocated by native code - * @param value String to free - */ - EXPORTED void InfiniFrame_FreeString(AutoString value) { - if (value == nullptr) - return; -#ifdef _WIN32 - delete[] value; -#elif __linux__ - g_free(value); -#elif __APPLE__ - free(value); -#else - free(value); -#endif + }); } - /** - * @brief Free string array allocated by native code - * @param values String array to free - * @param count Number of strings in array - */ - EXPORTED void InfiniFrame_FreeStringArray(AutoString* values, const int count) { - if (values == nullptr) - return; + EXPORTED InteropStatus InfiniFrame_Center(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Center(); }); } + EXPORTED InteropStatus InfiniFrame_ClearBrowserAutoFill(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->ClearBrowserAutoFill(); }); } + EXPORTED InteropStatus InfiniFrame_Close(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Close(); }); } - for (int i = 0; i < count; ++i) { - InfiniFrame_FreeString(values[i]); - } + EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetTransparentEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetContextMenuEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetContextMenuEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetZoomEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetZoomEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetDevToolsEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetDevToolsEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetFullScreen(InfiniFrameWindow* instance, bool* fullScreen) { + ResetOut(fullScreen, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(fullScreen, "fullScreen")) throw std::invalid_argument("Argument 'fullScreen' is null."); + window->GetFullScreen(fullScreen); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetGrantBrowserPermissions(InfiniFrameWindow* instance, bool* grant) { + ResetOut(grant, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(grant, "grant")) throw std::invalid_argument("Argument 'grant' is null."); + window->GetGrantBrowserPermissions(grant); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetUserAgent(InfiniFrameWindow* instance, AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetUserAgent(); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetMediaAutoplayEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetMediaAutoplayEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetFileSystemAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetFileSystemAccessEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetWebSecurityEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetWebSecurityEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetJavascriptClipboardAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetJavascriptClipboardAccessEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetMediaStreamEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetMediaStreamEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetSmoothScrollingEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetSmoothScrollingEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetMaximized(InfiniFrameWindow* instance, bool* isMaximized) { + ResetOut(isMaximized, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(isMaximized, "isMaximized")) throw std::invalid_argument("Argument 'isMaximized' is null."); + window->GetMaximized(isMaximized); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetMinimized(InfiniFrameWindow* instance, bool* isMinimized) { + ResetOut(isMinimized, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(isMinimized, "isMinimized")) throw std::invalid_argument("Argument 'isMinimized' is null."); + window->GetMinimized(isMinimized); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetIgnoreCertificateErrorsEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetIgnoreCertificateErrorsEnabled(enabled); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetPosition(InfiniFrameWindow* instance, int* x, int* y) { + ResetOut2(x, y, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(x, "x") || !EnsureNotNull(y, "y")) throw std::invalid_argument("GetPosition out argument is null."); + window->GetPosition(x, y); + }); + } + EXPORTED InteropStatus InfiniFrame_GetResizable(InfiniFrameWindow* instance, bool* resizable) { + ResetOut(resizable, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(resizable, "resizable")) throw std::invalid_argument("Argument 'resizable' is null."); + window->GetResizable(resizable); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetScreenDpi(InfiniFrameWindow* instance, unsigned int* value) { + ResetOut(value, static_cast(0)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetScreenDpi(); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetSize(InfiniFrameWindow* instance, int* width, int* height) { + ResetOut2(width, height, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetSize out argument is null."); + window->GetSize(width, height); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetMaxSize(InfiniFrameWindow* instance, int* width, int* height) { + ResetOut2(width, height, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetMaxSize out argument is null."); + window->GetMaxSize(width, height); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetMinSize(InfiniFrameWindow* instance, int* width, int* height) { + ResetOut2(width, height, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetMinSize out argument is null."); + window->GetMinSize(width, height); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetTitle(InfiniFrameWindow* instance, AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetTitle(); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetTopmost(InfiniFrameWindow* instance, bool* topmost) { + ResetOut(topmost, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(topmost, "topmost")) throw std::invalid_argument("Argument 'topmost' is null."); + window->GetTopmost(topmost); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetZoom(InfiniFrameWindow* instance, int* zoom) { + ResetOut(zoom, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(zoom, "zoom")) throw std::invalid_argument("Argument 'zoom' is null."); + window->GetZoom(zoom); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetFocused(InfiniFrameWindow* instance, bool* isFocused) { + ResetOut(isFocused, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(isFocused, "isFocused")) throw std::invalid_argument("Argument 'isFocused' is null."); + window->GetFocused(isFocused); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetIconFileName(InfiniFrameWindow* instance, AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetIconFileName(); + }); + } + + EXPORTED InteropStatus InfiniFrame_NavigateToString(InfiniFrameWindow* instance, const AutoString content) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(content, "content")) throw std::invalid_argument("Argument 'content' is null."); + window->NavigateToString(content); + }); + } + + EXPORTED InteropStatus InfiniFrame_NavigateToUrl(InfiniFrameWindow* instance, const AutoString url) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(url, "url")) throw std::invalid_argument("Argument 'url' is null."); + window->NavigateToUrl(url); + }); + } + + EXPORTED InteropStatus InfiniFrame_Restore(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Restore(); }); } + + EXPORTED InteropStatus InfiniFrame_SendWebMessage(InfiniFrameWindow* instance, const AutoString message) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(message, "message")) throw std::invalid_argument("Argument 'message' is null."); + window->SendWebMessage(message); + }); + } + + EXPORTED InteropStatus InfiniFrame_SetTransparentEnabled(InfiniFrameWindow* instance, const bool enabled) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetTransparentEnabled(enabled); }); } + EXPORTED InteropStatus InfiniFrame_SetContextMenuEnabled(InfiniFrameWindow* instance, const bool enabled) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetContextMenuEnabled(enabled); }); } + EXPORTED InteropStatus InfiniFrame_SetZoomEnabled(InfiniFrameWindow* instance, const bool enabled) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetZoomEnabled(enabled); }); } + EXPORTED InteropStatus InfiniFrame_SetDevToolsEnabled(InfiniFrameWindow* instance, const bool enabled) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetDevToolsEnabled(enabled); }); } + EXPORTED InteropStatus InfiniFrame_SetFullScreen(InfiniFrameWindow* instance, const bool fullScreen) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFullScreen(fullScreen); }); } + + EXPORTED InteropStatus InfiniFrame_SetIconFile(InfiniFrameWindow* instance, const AutoString filename) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(filename, "filename")) throw std::invalid_argument("Argument 'filename' is null."); + window->SetIconFile(filename); + }); + } + + EXPORTED InteropStatus InfiniFrame_SetMaximized(InfiniFrameWindow* instance, const bool maximized) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMaximized(maximized); }); } + EXPORTED InteropStatus InfiniFrame_SetMaxSize(InfiniFrameWindow* instance, const int width, const int height) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMaxSize(width, height); }); } + EXPORTED InteropStatus InfiniFrame_SetMinimized(InfiniFrameWindow* instance, const bool minimized) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMinimized(minimized); }); } + EXPORTED InteropStatus InfiniFrame_SetMinSize(InfiniFrameWindow* instance, const int width, const int height) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMinSize(width, height); }); } + EXPORTED InteropStatus InfiniFrame_SetPosition(InfiniFrameWindow* instance, const int x, const int y) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetPosition(x, y); }); } + EXPORTED InteropStatus InfiniFrame_SetResizable(InfiniFrameWindow* instance, const bool resizable) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetResizable(resizable); }); } + EXPORTED InteropStatus InfiniFrame_SetSize(InfiniFrameWindow* instance, const int width, const int height) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetSize(width, height); }); } + + EXPORTED InteropStatus InfiniFrame_SetTitle(InfiniFrameWindow* instance, const AutoString title) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(title, "title")) throw std::invalid_argument("Argument 'title' is null."); + window->SetTitle(title); + }); + } + + EXPORTED InteropStatus InfiniFrame_SetTopmost(InfiniFrameWindow* instance, const bool topmost) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetTopmost(topmost); }); } + EXPORTED InteropStatus InfiniFrame_SetZoom(InfiniFrameWindow* instance, const int zoom) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetZoom(zoom); }); } + + EXPORTED InteropStatus InfiniFrame_ShowNotification(InfiniFrameWindow* instance, const AutoString title, const AutoString body) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(title, "title") || !EnsureNotNull(body, "body")) throw std::invalid_argument("ShowNotification argument is null."); + window->ShowNotification(title, body); + }); + } + + EXPORTED InteropStatus InfiniFrame_WaitForExit(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->WaitForExit(); }); } + + EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { + return RunExportStatus([&] { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); #ifdef _WIN32 - delete[] values; + delete[] value; #elif __linux__ - delete[] values; -#elif __APPLE__ - free(values); + g_free(value); #else - free(values); + free(value); #endif - } - - /** - * @brief Show open file dialog - * @param inst InfiniFrame instance - * @param title Dialog title - * @param defaultPath Default path - * @param multiSelect Allow multiple selection - * @param filters File filters - * @param filterCount Number of filters - * @param resultCount Output: number of selected files - * @return Array of selected file paths - */ - EXPORTED AutoString* InfiniFrame_ShowOpenFile( - InfiniFrameWindow* inst, - const AutoString title, - const AutoString defaultPath, - const bool multiSelect, - AutoString* filters, - const int filterCount, - int* resultCount - ) { - return inst->GetDialog()->ShowOpenFile(title, defaultPath, multiSelect, filters, filterCount, resultCount); - } - - /** - * @brief Show open folder dialog - * @param inst InfiniFrame instance - * @param title Dialog title - * @param defaultPath Default path - * @param multiSelect Allow multiple selection - * @param resultCount Output: number of selected folders - * @return Array of selected folder paths - */ - EXPORTED AutoString* InfiniFrame_ShowOpenFolder( - InfiniFrameWindow* inst, - const AutoString title, - const AutoString defaultPath, - const bool multiSelect, - int* resultCount - ) { - return inst->GetDialog()->ShowOpenFolder(title, defaultPath, multiSelect, resultCount); - } - - /** - * @brief Show save file dialog - * @param inst InfiniFrame instance - * @param title Dialog title - * @param defaultPath Default path - * @param filters File filters - * @param filterCount Number of filters - * @param defaultFileName Default file name - * @return Selected file path - */ - EXPORTED AutoString InfiniFrame_ShowSaveFile( - InfiniFrameWindow* inst, - const AutoString title, - const AutoString defaultPath, - AutoString* filters, - const int filterCount, - const AutoString defaultFileName - ) { - return inst->GetDialog()->ShowSaveFile(title, defaultPath, filters, filterCount, defaultFileName); - } - - /** - * @brief Show message dialog - * @param inst InfiniFrame instance - * @param title Dialog title - * @param text Message text - * @param buttons Button configuration - * @param icon Icon type - * @return User response - */ - EXPORTED DialogResult InfiniFrame_ShowMessage( - InfiniFrameWindow* inst, - const AutoString title, - const AutoString text, - const DialogButtons buttons, - const DialogIcon icon - ) { - return inst->GetDialog()->ShowMessage(title, text, buttons, icon); - } - - /** - * @brief Add custom scheme name - * @param instance InfiniFrame instance - * @param scheme Scheme name to add - */ - EXPORTED void InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { - instance->AddCustomSchemeName(scheme); - } - - /** - * @brief Get all monitors - * @param instance InfiniFrame instance - * @param callback Callback function to receive monitor info - */ - EXPORTED void InfiniFrame_GetAllMonitors(InfiniFrameWindow* instance, const GetAllMonitorsCallback callback) { - instance->GetAllMonitors(callback); - } - - /** - * @brief Set closing callback - * @param instance InfiniFrame instance - * @param callback Closing callback - */ - EXPORTED void InfiniFrame_SetClosingCallback(InfiniFrameWindow* instance, const ClosingCallback callback) { - instance->SetClosingCallback(callback); - } - - EXPORTED void InfiniFrame_setClosedClosedCallback(InfiniFrameWindow* instance, const ClosedCallback callback) - { instance->SetClosedCallback(callback); - } - - /** - * @brief Set focus-in callback - * @param instance InfiniFrame instance - * @param callback Focus-in callback - */ - EXPORTED void InfiniFrame_SetFocusInCallback(InfiniFrameWindow* instance, const FocusInCallback callback) { - instance->SetFocusInCallback(callback); - } - - /** - * @brief Set focus-out callback - * @param instance InfiniFrame instance - * @param callback Focus-out callback - */ - EXPORTED void InfiniFrame_SetFocusOutCallback(InfiniFrameWindow* instance, const FocusOutCallback callback) { - instance->SetFocusOutCallback(callback); - } - - /** - * @brief Set moved callback - * @param instance InfiniFrame instance - * @param callback Moved callback - */ - EXPORTED void InfiniFrame_SetMovedCallback(InfiniFrameWindow* instance, const MovedCallback callback) { - instance->SetMovedCallback(callback); - } - - /** - * @brief Set resized callback - * @param instance InfiniFrame instance - * @param callback Resized callback - */ - EXPORTED void InfiniFrame_SetResizedCallback(InfiniFrameWindow* instance, const ResizedCallback callback) { - instance->SetResizedCallback(callback); - } - - /** - * @brief Invoke callback on UI thread - * @param instance InfiniFrame instance - * @param callback Callback to invoke - */ - EXPORTED void InfiniFrame_Invoke(InfiniFrameWindow* instance, const ACTION callback) { - instance->Invoke(callback); - } - - /** - * @brief Set window focused - * @param instance InfiniFrame instance - */ - EXPORTED void InfiniFrame_SetFocused(InfiniFrameWindow* instance) { - instance->SetFocused(); + }); + } + + EXPORTED InteropStatus InfiniFrame_FreeStringArray(AutoString* values, const int count) { + return RunExportStatus([&] { + if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + if (count < 0) throw std::invalid_argument("Argument 'count' must be >= 0."); + for (int i = 0; i < count; ++i) { + if (values[i] != nullptr) { + InfiniFrame_FreeString(values[i]); + } + } +#ifdef _WIN32 + delete[] values; +#elif __linux__ + delete[] values; +#else + free(values); +#endif + }); + } + + EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, AutoString* filters, const int filterCount, int* resultCount, AutoString** values) { + ResetOut(resultCount, 0); + ResetOut(values, static_cast(nullptr)); + return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); + if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); + *values = window->GetDialog()->ShowOpenFile(title, defaultPath, multiSelect, filters, filterCount, resultCount); + }); + } + + EXPORTED InteropStatus InfiniFrame_ShowOpenFolder(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, int* resultCount, AutoString** values) { + ResetOut(resultCount, 0); + ResetOut(values, static_cast(nullptr)); + return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); + if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + *values = window->GetDialog()->ShowOpenFolder(title, defaultPath, multiSelect, resultCount); + }); + } + + EXPORTED InteropStatus InfiniFrame_ShowSaveFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, AutoString* filters, const int filterCount, const AutoString defaultFileName, AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); + *value = window->GetDialog()->ShowSaveFile(title, defaultPath, filters, filterCount, defaultFileName); + }); + } + + EXPORTED InteropStatus InfiniFrame_ShowMessage(InfiniFrameWindow* inst, const AutoString title, const AutoString text, const DialogButtons buttons, const DialogIcon icon, DialogResult* value) { + ResetOut(value, DialogResult::Cancel); + return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetDialog()->ShowMessage(title, text, buttons, icon); + }); + } + + EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(scheme, "scheme")) throw std::invalid_argument("Argument 'scheme' is null."); + window->AddCustomSchemeName(scheme); + }); + } + + EXPORTED InteropStatus InfiniFrame_GetAllMonitors(InfiniFrameWindow* instance, const GetAllMonitorsCallback callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (callback == nullptr) throw std::invalid_argument("Argument 'callback' is null."); + window->GetAllMonitors(callback); + }); + } + + EXPORTED InteropStatus InfiniFrame_SetClosingCallback(InfiniFrameWindow* instance, const ClosingCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetClosingCallback(callback); }); } + EXPORTED InteropStatus InfiniFrame_setClosedClosedCallback(InfiniFrameWindow* instance, const ClosedCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetClosedCallback(callback); }); } + EXPORTED InteropStatus InfiniFrame_SetFocusInCallback(InfiniFrameWindow* instance, const FocusInCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFocusInCallback(callback); }); } + EXPORTED InteropStatus InfiniFrame_SetFocusOutCallback(InfiniFrameWindow* instance, const FocusOutCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFocusOutCallback(callback); }); } + EXPORTED InteropStatus InfiniFrame_SetMovedCallback(InfiniFrameWindow* instance, const MovedCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMovedCallback(callback); }); } + EXPORTED InteropStatus InfiniFrame_SetResizedCallback(InfiniFrameWindow* instance, const ResizedCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetResizedCallback(callback); }); } + + EXPORTED InteropStatus InfiniFrame_Invoke(InfiniFrameWindow* instance, const ACTION callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (callback == nullptr) throw std::invalid_argument("Argument 'callback' is null."); + window->Invoke(callback); + }); + } + + EXPORTED InteropStatus InfiniFrame_SetFocused(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->SetFocused(); }); } + + EXPORTED InteropStatus InfiniFrame_GetLastErrorMessage(AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunExportStatus([&] { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = GetLastErrorMessageCopy(); + }); } } diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Exports/ExportGuards.h new file mode 100644 index 000000000..4c41d3750 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/ExportGuards.h @@ -0,0 +1,203 @@ +#pragma once + +#ifndef INFINIFRAME_EXPORT_GUARDS_H +#define INFINIFRAME_EXPORT_GUARDS_H + +#include +#include +#include +#include +#include + +#include "../Core/InfiniFrame.h" + +#ifdef _WIN32 +#include +#endif + +enum class InteropStatus : int { + Success = 0, + InvalidArgument = 22, + OperationFailed = 14 +}; + +namespace infiniframe::exports { + namespace detail { + inline thread_local std::string g_lastErrorMessage; + + inline void SetLastErrorCode(const InteropStatus status) noexcept { +#ifdef _WIN32 + SetLastError(static_cast(status)); +#else + errno = static_cast(status); +#endif + } + + inline void ClearLastErrorCode() noexcept { +#ifdef _WIN32 + SetLastError(0); +#else + errno = 0; +#endif + } + + inline void SetFailure(const InteropStatus status, std::string message) noexcept { + g_lastErrorMessage = std::move(message); + SetLastErrorCode(status); + } + + inline void SetSuccess() noexcept { + g_lastErrorMessage.clear(); + ClearLastErrorCode(); + } + + inline InteropStatus TranslateException(const std::exception& ex) noexcept { + if (dynamic_cast(&ex) != nullptr) { + SetFailure(InteropStatus::InvalidArgument, ex.what()); + return InteropStatus::InvalidArgument; + } + + SetFailure(InteropStatus::OperationFailed, ex.what()); + return InteropStatus::OperationFailed; + } + +#ifdef _WIN32 + inline AutoString AllocateErrorMessageString(const std::string& value) { + if (value.empty()) { + return nullptr; + } + + const int wideCount = MultiByteToWideChar( + CP_UTF8, + 0, + value.c_str(), + static_cast(value.size()), + nullptr, + 0 + ); + if (wideCount <= 0) { + return nullptr; + } + + auto* buffer = new wchar_t[wideCount + 1]; + const int converted = MultiByteToWideChar( + CP_UTF8, + 0, + value.c_str(), + static_cast(value.size()), + buffer, + wideCount + ); + if (converted <= 0) { + delete[] buffer; + return nullptr; + } + + buffer[converted] = L'\0'; + return buffer; + } +#else + inline AutoString AllocateErrorMessageString(const std::string& value) { + if (value.empty()) { + return nullptr; + } + + return AllocateStringCopy(value); + } +#endif + } + + inline AutoString GetLastErrorMessageCopy() { + return detail::AllocateErrorMessageString(detail::g_lastErrorMessage); + } + + template + inline void ResetOut(T* outValue, const T fallback = {}) noexcept { + if (outValue != nullptr) { + *outValue = fallback; + } + } + + template + inline void ResetOut2(T* first, T* second, const T fallback = {}) noexcept { + ResetOut(first, fallback); + ResetOut(second, fallback); + } + + template + inline bool EnsureNotNull(T* value, const char* argumentName) noexcept { + if (value != nullptr) { + return true; + } + + detail::SetFailure(InteropStatus::InvalidArgument, std::string("Argument '") + argumentName + "' is null."); + return false; + } + + template + inline InteropStatus RunExportStatus(Fn&& fn) noexcept { + try { + std::forward(fn)(); + detail::SetSuccess(); + return InteropStatus::Success; + } + catch (const std::exception& ex) { + return detail::TranslateException(ex); + } + catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return InteropStatus::OperationFailed; + } + } + + template + inline InteropStatus RunWindowExportStatus(InfiniFrameWindow* instance, Fn&& fn) noexcept { + return RunExportStatus([&] { + if (!EnsureNotNull(instance, "instance")) { + throw std::invalid_argument("Argument 'instance' is null."); + } + + std::forward(fn)(instance); + }); + } + + template + inline T RunWindowReturnExport(InfiniFrameWindow* instance, T fallback, Fn&& fn) noexcept { + try { + if (!EnsureNotNull(instance, "instance")) { + return fallback; + } + + T value = std::forward(fn)(instance); + detail::SetSuccess(); + return value; + } + catch (const std::exception& ex) { + detail::TranslateException(ex); + return fallback; + } + catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return fallback; + } + } + + template + inline T RunReturnExport(T fallback, Fn&& fn) noexcept { + try { + T value = std::forward(fn)(); + detail::SetSuccess(); + return value; + } + catch (const std::exception& ex) { + detail::TranslateException(ex); + return fallback; + } + catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return fallback; + } + } +} + +#endif // INFINIFRAME_EXPORT_GUARDS_H diff --git a/src/InfiniFrame.Shared/Utilities/InvokeUtility.cs b/src/InfiniFrame.Shared/Utilities/InvokeUtility.cs index 7c6a3fcd1..bb3fb494e 100644 --- a/src/InfiniFrame.Shared/Utilities/InvokeUtility.cs +++ b/src/InfiniFrame.Shared/Utilities/InvokeUtility.cs @@ -53,5 +53,22 @@ public static T InvokeAndReturn(IInfiniFrameWindow window, FuncWithOut cal return value!; } + public static T InvokeAndReturn(IInfiniFrameWindow window, FuncWithOutResult callback, Action? validateResult = null) { + T? value = default; + TResult? result = default; + // ReSharper disable once RedundantAssignment + bool completed = false; + window.Invoke(() => { + result = callback(window.InstanceHandle, out value); + completed = true; + }); + Debug.Assert(completed, "Invoke must be synchronous — callback did not complete before Invoke returned."); + if (validateResult is not null && result is not null) { + validateResult(result); + } + return value!; + } + internal delegate void FuncWithOut(IntPtr handle, out T value); + internal delegate TResult FuncWithOutResult(IntPtr handle, out T value); } diff --git a/src/InfiniFrame/Window/InfiniFrameWindow.cs b/src/InfiniFrame/Window/InfiniFrameWindow.cs index b8529a469..0adbb86da 100644 --- a/src/InfiniFrame/Window/InfiniFrameWindow.cs +++ b/src/InfiniFrame/Window/InfiniFrameWindow.cs @@ -50,9 +50,21 @@ public sealed class InfiniFrameWindow : IInfiniFrameWindow { /// /// The delegate encapsulating a method / action to be executed in the UI thread. public void Invoke(Action workItem) { + static void RunWithNativeStatusCheck(Action action) { + Marshal.SetLastPInvokeError(0); + action(); + InfiniFrameNative.EnsureSucceeded(InfiniFrameNativeStatus.Success, "Invoke"); + } + // If we're already on the UI thread, no need to dispatch - if (Environment.CurrentManagedThreadId == ManagedThreadId) workItem(); - else InfiniFrameNative.Invoke(InstanceHandle, workItem.Invoke); + if (Environment.CurrentManagedThreadId == ManagedThreadId) { + RunWithNativeStatusCheck(workItem); + } + else { + InfiniFrameNative.EnsureSucceeded( + InfiniFrameNative.Invoke(InstanceHandle, () => RunWithNativeStatusCheck(workItem)), + nameof(InfiniFrameNative.Invoke)); + } } /// @@ -70,8 +82,7 @@ public void WaitForClose() { } catch (Exception ex) when (ExceptionsUtility.IsNonFatalException(ex)) { int lastError = 0; - if (OperatingSystem.IsWindows()) - lastError = Marshal.GetLastWin32Error(); + if (OperatingSystem.IsWindows()) lastError = Marshal.GetLastWin32Error(); Logger.LogError(ex, "Error #{LastErrorCode} while running message loop", lastError); throw new ApplicationException($"Native code exception. Error # {lastError} See inner exception for details.", ex); @@ -274,7 +285,9 @@ public void SendNotification(string title, string body) { string[] nativeFilters = GetNativeFilters(filters); Invoke(() => { - IntPtr ptrResult = InfiniFrameNative.ShowSaveFile(InstanceHandle, title, defaultPath, nativeFilters, filters.Length, null); + InfiniFrameNative.EnsureSucceeded( + InfiniFrameNative.ShowSaveFile(InstanceHandle, title, defaultPath, nativeFilters, filters.Length, null, out IntPtr ptrResult), + nameof(InfiniFrameNative.ShowSaveFile)); if (ptrResult == IntPtr.Zero) return; try { @@ -320,7 +333,11 @@ public void SendNotification(string title, string body) { /// public InfiniFrameDialogResult ShowMessage(string title, string? text, InfiniFrameDialogButtons buttons = InfiniFrameDialogButtons.Ok, InfiniFrameDialogIcon icon = InfiniFrameDialogIcon.Info) { var result = InfiniFrameDialogResult.Cancel; - Invoke(() => result = InfiniFrameNative.ShowMessage(InstanceHandle, title, text ?? string.Empty, buttons, icon)); + Invoke(() => { + InfiniFrameNative.EnsureSucceeded( + InfiniFrameNative.ShowMessage(InstanceHandle, title, text ?? string.Empty, buttons, icon, out result), + nameof(InfiniFrameNative.ShowMessage)); + }); return result; } @@ -357,11 +374,20 @@ public void Initialize() { // All C++ exceptions will bubble up to here. try { if (OperatingSystem.IsWindows()) - Invoke(() => InfiniFrameNative.RegisterWin32(NativeType)); + Invoke(() => { + InfiniFrameNative.RegisterWin32(NativeType); + }); else if (OperatingSystem.IsMacOS()) - Invoke(InfiniFrameNative.RegisterMac); - - Invoke(() => InstanceHandle = InfiniFrameNative.Constructor(in startupParameters)); + Invoke(() => { + InfiniFrameNative.RegisterMac(); + }); + + Invoke(() => { + InfiniFrameNative.EnsureSucceeded( + InfiniFrameNative.Constructor(in startupParameters, out IntPtr instanceHandle), + nameof(InfiniFrameNative.Constructor)); + InstanceHandle = instanceHandle; + }); } catch (Exception ex) when (ExceptionsUtility.IsNonFatalException(ex)) { int lastError = 0; @@ -396,7 +422,10 @@ public void Initialize() { string[] nativeFilters = GetNativeFilters(filters, foldersOnly); Invoke(() => { - IntPtr ptrResults = foldersOnly ? InfiniFrameNative.ShowOpenFolder(InstanceHandle, title, defaultPath, multiSelect, out int resultCount) : InfiniFrameNative.ShowOpenFile(InstanceHandle, title, defaultPath, multiSelect, nativeFilters, nativeFilters.Length, out resultCount); + InfiniFrameNativeStatus status = foldersOnly + ? InfiniFrameNative.ShowOpenFolder(InstanceHandle, title, defaultPath, multiSelect, out int resultCount, out IntPtr ptrResults) + : InfiniFrameNative.ShowOpenFile(InstanceHandle, title, defaultPath, multiSelect, nativeFilters, nativeFilters.Length, out resultCount, out ptrResults); + InfiniFrameNative.EnsureSucceeded(status, foldersOnly ? nameof(InfiniFrameNative.ShowOpenFolder) : nameof(InfiniFrameNative.ShowOpenFile)); if (resultCount == 0 || ptrResults == IntPtr.Zero) return; @@ -449,7 +478,10 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// Thrown when accessed from a non-Windows platform. [DebuggerBrowsable(DebuggerBrowsableState.Never)] public IntPtr WindowHandle => OperatingSystem.IsWindows() - ? InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetWindowHandlerWin32) + ? InvokeUtility.InvokeAndReturn( + this, + InfiniFrameNative.GetWindowHandlerWin32, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetWindowHandlerWin32))) : IntPtr.Zero; /// @@ -484,7 +516,10 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// An ApplicationException is thrown if the window hasn't been initialized yet. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public uint ScreenDpi => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetScreenDpi); + public uint ScreenDpi => InvokeUtility.InvokeAndReturn( + this, + InfiniFrameNative.GetScreenDpi, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetScreenDpi))); /// /// Gets a unique GUID to identify the native window. @@ -516,48 +551,51 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool Transparent => OperatingSystem.IsWindows() ? Configuration.StartupParameters.Transparent// on windows it can only be set at startup - : InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTransparentEnabled); + : InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTransparentEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetTransparentEnabled))); /// /// When true, the user can access the browser control's context menu. /// By default, this is set to true. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool ContextMenuEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetContextMenuEnabled); + public bool ContextMenuEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetContextMenuEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetContextMenuEnabled))); /// /// When true, the user can access the browser control's developer tools. /// By default, this is set to true. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool DevToolsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetDevToolsEnabled); + public bool DevToolsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetDevToolsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetDevToolsEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool MediaAutoplayEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMediaAutoplayEnabled); + public bool MediaAutoplayEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMediaAutoplayEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMediaAutoplayEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public string? UserAgent => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetUserAgent); + public string? UserAgent => InvokeUtility.InvokeAndReturn( + this, + InfiniFrameNative.GetUserAgent, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetUserAgent))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool FileSystemAccessEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFileSystemAccessEnabled); + public bool FileSystemAccessEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFileSystemAccessEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFileSystemAccessEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool WebSecurityEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetWebSecurityEnabled); + public bool WebSecurityEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetWebSecurityEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetWebSecurityEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool JavascriptClipboardAccessEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetJavascriptClipboardAccessEnabled); + public bool JavascriptClipboardAccessEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetJavascriptClipboardAccessEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetJavascriptClipboardAccessEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool MediaStreamEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMediaStreamEnabled); + public bool MediaStreamEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMediaStreamEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMediaStreamEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool SmoothScrollingEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetSmoothScrollingEnabled); + public bool SmoothScrollingEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetSmoothScrollingEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetSmoothScrollingEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool IgnoreCertificateErrorsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetIgnoreCertificateErrorsEnabled); + public bool IgnoreCertificateErrorsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetIgnoreCertificateErrorsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetIgnoreCertificateErrorsEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool NotificationsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetNotificationsEnabled); + public bool NotificationsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetNotificationsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetNotificationsEnabled))); /// /// This property returns or sets the fullscreen status of the window. @@ -565,34 +603,47 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// By default, this is set to false. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool FullScreen => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFullScreen); + public bool FullScreen => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFullScreen, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFullScreen))); /// /// Gets whether the native browser control grants all requests for access to local resources /// such as the user's camera and microphone. By default, this is set to true. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool GrantBrowserPermissions => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetGrantBrowserPermissions); + public bool GrantBrowserPermissions => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetGrantBrowserPermissions, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetGrantBrowserPermissions))); /// /// Gets the Height property of the native window in pixels. /// The default value is 0. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int Height => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetHeight); + public int Height => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out int value) => InfiniFrameNative.GetSize(handle, out _, out value), + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetSize))); /// /// Gets the icon file for the native window title bar. /// The file must be located on the local machine and cannot be a URL. The default is none. /// - public string IconFilePath => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetIconFileName); + public string IconFilePath => InvokeUtility.InvokeAndReturn( + this, + InfiniFrameNative.GetIconFileName, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetIconFileName))); /// /// Gets the native window Left (X) and Top coordinates (Y) in pixels. /// Default is 0,0 that means the window will be aligned to the top-left edge of the screen. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public Point Location => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetPosition); + public Point Location => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out Point value) => { + InfiniFrameNativeStatus status = InfiniFrameNative.GetPosition(handle, out int left, out int top); + value = new Point(left, top); + return status; + }, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetPosition))); /// /// Gets the native window Left (X) coordinate in pixels. @@ -600,76 +651,112 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// The default value is 0, which means the window will be aligned to the left edge of the screen. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int Left => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetLeft); + public int Left => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out int value) => InfiniFrameNative.GetPosition(handle, out value, out _), + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetPosition))); /// /// Gets whether the native window is maximized. /// Default is false. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool Maximized => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMaximized); + public bool Maximized => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMaximized, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMaximized))); /// /// Gets whether the native window is currently within focus /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool Focused => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFocused); + public bool Focused => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFocused, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFocused))); /// /// Gets the maximum size of the native window in pixels. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public Size MaxSize => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMaxSize); + public Size MaxSize => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out Size value) => { + InfiniFrameNativeStatus status = InfiniFrameNative.GetMaxSize(handle, out int width, out int height); + value = new Size(width, height); + return status; + }, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMaxSize))); /// /// Gets the native window maximum height in pixels. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int MaxHeight => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMaxHeight); + public int MaxHeight => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out int value) => InfiniFrameNative.GetMaxSize(handle, out _, out value), + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMaxSize))); /// /// Gets the native window maximum width in pixels. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int MaxWidth => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMaxWidth); + public int MaxWidth => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out int value) => InfiniFrameNative.GetMaxSize(handle, out value, out _), + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMaxSize))); /// /// Gets whether the native window is minimized (hidden). /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool Minimized => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMinimized); + public bool Minimized => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMinimized, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMinimized))); /// /// Gets the minimum size of the native window in pixels. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public Size MinSize => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMinSize); + public Size MinSize => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out Size value) => { + InfiniFrameNativeStatus status = InfiniFrameNative.GetMinSize(handle, out int width, out int height); + value = new Size(width, height); + return status; + }, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMinSize))); /// /// Gets the native window minimum height in pixels. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int MinHeight => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMinHeight); + public int MinHeight => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out int value) => InfiniFrameNative.GetMinSize(handle, out _, out value), + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMinSize))); /// /// Gets the native window minimum width in pixels. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int MinWidth => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMinWidth); + public int MinWidth => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out int value) => InfiniFrameNative.GetMinSize(handle, out value, out _), + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMinSize))); /// /// Gets whether the user can resize the native window. /// Default is true. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool Resizable => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetResizable); + public bool Resizable => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetResizable, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetResizable))); /// /// Gets the native window Size. This represents the width and the height of the window in pixels. /// The default Size is 0,0. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public Size Size => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetSize); + public Size Size => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out Size value) => { + InfiniFrameNativeStatus status = InfiniFrameNative.GetSize(handle, out int width, out int height); + value = new Size(width, height); + return status; + }, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetSize))); /// /// Gets platform-specific initialization parameters for the native browser control on startup. @@ -745,28 +832,37 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// The default is "InfiniFrame". /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public string? Title => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTitle); + public string? Title => InvokeUtility.InvokeAndReturn( + this, + InfiniFrameNative.GetTitle, + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetTitle))); /// /// Gets the native window Top (Y) coordinate in pixels. /// Default is 0. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int Top => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTop); + public int Top => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out int value) => InfiniFrameNative.GetPosition(handle, out _, out value), + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetPosition))); /// /// Gets whether the native window is always at the top of the z-order. /// Default is false. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool TopMost => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTopmost); + public bool TopMost => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTopmost, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetTopmost))); /// /// Gets the native window width in pixels. /// Default is 0. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int Width => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetWidth); + public int Width => InvokeUtility.InvokeAndReturn( + this, + (IntPtr handle, out int value) => InfiniFrameNative.GetSize(handle, out value, out _), + s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetSize))); /// /// Gets the native browser control . @@ -774,9 +870,9 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// /// 100 = 100%, 50 = 50% [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int Zoom => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetZoom); + public int Zoom => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetZoom, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetZoom))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool ZoomEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetZoomEnabled); + public bool ZoomEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetZoomEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetZoomEnabled))); #endregion } diff --git a/src/InfiniFrame/Window/InfiniFrameWindowExtensions.cs b/src/InfiniFrame/Window/InfiniFrameWindowExtensions.cs index 80a4fa255..65ebf7e3b 100644 --- a/src/InfiniFrame/Window/InfiniFrameWindowExtensions.cs +++ b/src/InfiniFrame/Window/InfiniFrameWindowExtensions.cs @@ -756,8 +756,20 @@ public static T SetTitle(this T window, string? title) where T : class, IInfi window.Logger.LogDebug(".SetTitle({Title})", title); window.Invoke(() => { - IntPtr ptr = InfiniFrameNative.GetTitle(window.InstanceHandle); - string? oldTitle = InfiniFrameNative.PtrToNativeString(ptr); + InfiniFrameNative.EnsureSucceeded( + InfiniFrameNative.GetTitle(window.InstanceHandle, out IntPtr ptr), + nameof(InfiniFrameNative.GetTitle)); + + string? oldTitle; + try { + oldTitle = InfiniFrameNative.PtrToNativeString(ptr); + } + finally { + if (ptr != IntPtr.Zero) { + InfiniFrameNative.FreeString(ptr); + } + } + if (title == oldTitle) return; InfiniFrameNative.SetTitle( diff --git a/tests/InfiniFrameTests/InfiniFrameNativeParameterTests.cs b/tests/InfiniFrameTests/InfiniFrameNativeParameterTests.cs index 049399028..4d7143435 100644 --- a/tests/InfiniFrameTests/InfiniFrameNativeParameterTests.cs +++ b/tests/InfiniFrameTests/InfiniFrameNativeParameterTests.cs @@ -11,6 +11,41 @@ namespace InfiniFrameTests; // --------------------------------------------------------------------------------------------------------------------- public class InfiniFrameNativeParameterTests { + [Test] + public async Task NativeExport_InvalidArgument_SetsDeterministicLastErrorAndMessage(CancellationToken ct = default) { + // Act + InfiniFrameNative.FreeString(IntPtr.Zero); + int lastError = Marshal.GetLastPInvokeError(); + string? message = InfiniFrameNative.GetLastErrorMessage(); + + // Assert + await Assert.That(lastError).IsEqualTo(22); + await Assert.That(message).IsNotNull(); + await Assert.That(message!).Contains("value"); + } + + [Test] + public async Task NativeExport_Success_ClearsLastError(CancellationToken ct = default) { + IntPtr[] customSchemeNames = new IntPtr[16]; + IntPtr newParametersPtr = IntPtr.Zero; + + try { + var parameters = new InfiniFrameNativeParameters { + StartUrl = "https://example.org", + CustomSchemeNames = customSchemeNames, + Size = Marshal.SizeOf() + }; + + newParametersPtr = InfiniFrameNativeTesting.NativeParametersReturnAsIsPtr(ref parameters); + + int lastError = Marshal.GetLastPInvokeError(); + await Assert.That(lastError).IsEqualTo(0); + } + finally { + InfiniFrameNativeTesting.FreeInitParams(newParametersPtr); + } + } + // This test should onl fails if the InfiniFrameNativeParameterTests C# struct is wrongly defined // and has parameters in the wrong order, compared to the struct on the c++ side. [Test] From 28a274538aa09c841b926d7b0720b7d8e7b2d0e9 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 18:14:10 +0200 Subject: [PATCH 02/86] Split `Exports.cpp` into modular files: `Exports.Dialog.cpp` and `Exports.Events.cpp`, improving maintainability and organization. Removed unused and redundant code. --- .../LibraryImports/InfiniFrameNative.cs | 21 +- .../Native/CMakeLists.txt | 20 +- .../Native/Exports.cpp | 470 ------------ .../Native/Exports/Exports.Dialog.cpp | 41 ++ .../Native/Exports/Exports.Events.cpp | 48 ++ .../Native/Exports/Exports.Lifecycle.cpp | 31 + .../Native/Exports/Exports.Memory.cpp | 43 ++ .../Native/Exports/Exports.Platform.cpp | 39 + .../Native/Exports/Exports.Shared.h | 28 + .../Native/Exports/Exports.WindowCommands.cpp | 117 +++ .../Native/Exports/Exports.WindowState.cpp | 219 ++++++ .../Platform/Linux/Window.Gtk.Internal.h | 40 ++ .../Native/Platform/Linux/Window.cpp | 558 +-------------- .../Platform/Linux/WindowEvents.Gtk.cpp | 113 +++ .../Platform/Linux/WindowLifecycle.Gtk.cpp | 79 +++ .../Native/Platform/Linux/WindowState.Gtk.cpp | 336 +++++++++ .../Platform/Mac/Window.Cocoa.Internal.h | 38 + .../Native/Platform/Mac/Window.mm | 644 +---------------- .../Native/Platform/Mac/WindowEvents.Cocoa.mm | 151 ++++ .../Platform/Mac/WindowLifecycle.Cocoa.mm | 77 ++ .../Native/Platform/Mac/WindowState.Cocoa.mm | 383 ++++++++++ .../Platform/Windows/Window.Win32.Internal.h | 66 ++ .../Native/Platform/Windows/Window.cpp | 666 +----------------- .../Platform/Windows/WindowEvents.Win32.cpp | 137 ++++ .../Platform/Windows/WindowState.Win32.cpp | 462 ++++++++++++ 25 files changed, 2487 insertions(+), 2340 deletions(-) delete mode 100644 src/InfiniFrame.NativeBridge/Native/Exports.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/Exports.Shared.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowEvents.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowLifecycle.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowState.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowLifecycle.Cocoa.mm create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowState.Cocoa.mm create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEvents.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowState.Win32.cpp diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs index ab3285974..f348d97f3 100644 --- a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs +++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs @@ -372,14 +372,27 @@ internal static InfiniFrameNativeStatus GetIconFileName(IntPtr instance, out str } internal static InfiniFrameNativeStatus EnsureSucceeded(InfiniFrameNativeStatus status, string operationName) { - + int fallbackLastError = Marshal.GetLastPInvokeError(); if (status is InfiniFrameNativeStatus.Success && fallbackLastError is 0) return status; + + InfiniFrameNativeStatus fallbackStatus = GetLastErrorMessagePtr(out IntPtr ptr); - - string fallbackMessage = GetLastErrorMessage() ?? "No native error message provided."; - throw new ApplicationException($"Native interop call '{operationName}' failed with unknown status state. Fallback last error {fallbackLastError}. {fallbackMessage}"); + string? fallbackMessage; + if (fallbackStatus != InfiniFrameNativeStatus.Success || ptr == IntPtr.Zero) { + fallbackMessage = "No native error message provided."; + } + else { + try { + fallbackMessage = PtrToNativeString(ptr); + } + finally { + FreeString(ptr); + } + } + + throw new ApplicationException($"Native interop call '{operationName}' failed with unknown status state. Fallback last error {fallbackLastError}. {fallbackMessage} {fallbackStatus}"); } #endregion } diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index 441980030..6b2d4b1f3 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -31,7 +31,13 @@ infiniframe_setup_dependencies() # Source Files # ---------------------------------------------------------------------------------------------------------------------- set(COMMON_SOURCES - Exports.cpp + Exports/Exports.Platform.cpp + Exports/Exports.Lifecycle.cpp + Exports/Exports.WindowState.cpp + Exports/Exports.WindowCommands.cpp + Exports/Exports.Dialog.cpp + Exports/Exports.Events.cpp + Exports/Exports.Memory.cpp ) set(TEST_SOURCES @@ -40,12 +46,17 @@ set(TEST_SOURCES set(WINDOWS_SOURCES Platform/Windows/Window.cpp + Platform/Windows/WindowState.Win32.cpp + Platform/Windows/WindowEvents.Win32.cpp Platform/Windows/DarkMode.cpp Platform/Windows/Dialog.cpp ) set(LINUX_SOURCES Platform/Linux/Window.cpp + Platform/Linux/WindowLifecycle.Gtk.cpp + Platform/Linux/WindowState.Gtk.cpp + Platform/Linux/WindowEvents.Gtk.cpp Platform/Linux/Dialog.cpp ) @@ -58,6 +69,9 @@ set(MAC_SOURCES Platform/Mac/NSWindowBorderless.mm Platform/Mac/Dialog.mm Platform/Mac/Window.mm + Platform/Mac/WindowLifecycle.Cocoa.mm + Platform/Mac/WindowState.Cocoa.mm + Platform/Mac/WindowEvents.Cocoa.mm ) set(HEADER_FILES @@ -72,7 +86,9 @@ set(HEADER_FILES Types/Callbacks.h Utils/Common.h Utils/Event.h + Exports/Exports.Shared.h Platform/Windows/ToastHandler.h + Platform/Windows/Window.Win32.Internal.h Platform/Windows/DarkMode.h Platform/Mac/AppDelegate.h Platform/Mac/NavigationDelegate.h @@ -80,6 +96,8 @@ set(HEADER_FILES Platform/Mac/UiDelegate.h Platform/Mac/WindowDelegate.h Platform/Mac/UrlSchemeHandler.h + Platform/Linux/Window.Gtk.Internal.h + Platform/Mac/Window.Cocoa.Internal.h ) if (WIN32) diff --git a/src/InfiniFrame.NativeBridge/Native/Exports.cpp b/src/InfiniFrame.NativeBridge/Native/Exports.cpp deleted file mode 100644 index 1badb848e..000000000 --- a/src/InfiniFrame.NativeBridge/Native/Exports.cpp +++ /dev/null @@ -1,470 +0,0 @@ -#include "Core/InfiniFrame.h" -#include "Exports/ExportGuards.h" - -#ifdef __linux__ -#include -#endif - -#ifdef _WIN32 -#define EXPORTED __declspec(dllexport) -#else -#define EXPORTED -#endif - -using infiniframe::exports::EnsureNotNull; -using infiniframe::exports::GetLastErrorMessageCopy; -using infiniframe::exports::ResetOut; -using infiniframe::exports::ResetOut2; -using infiniframe::exports::RunExportStatus; -using infiniframe::exports::RunReturnExport; -using infiniframe::exports::RunWindowExportStatus; -using infiniframe::exports::RunWindowReturnExport; - -extern "C" { -#ifdef _WIN32 - EXPORTED InteropStatus InfiniFrame_register_win32(const HINSTANCE hInstance) { - return RunExportStatus([&] { - if (hInstance == nullptr) throw std::invalid_argument("Argument 'hInstance' is null."); - InfiniFrameWindow::Register(hInstance); - }); - } - - EXPORTED InteropStatus InfiniFrame_getHwnd_win32(InfiniFrameWindow* instance, HWND* value) { - ResetOut(value, static_cast(nullptr)); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - *value = window->getHwnd(); - }); - } - - EXPORTED InteropStatus InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindow*, const AutoString webView2RuntimePath) { - return RunExportStatus([&] { - if (!EnsureNotNull(webView2RuntimePath, "webView2RuntimePath")) throw std::invalid_argument("Argument 'webView2RuntimePath' is null."); - InfiniFrameWindow::SetWebView2RuntimePath(webView2RuntimePath); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetNotificationsEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetNotificationsEnabled(enabled); - }); - } -#elif __APPLE__ - EXPORTED InteropStatus InfiniFrame_register_mac() { - return RunExportStatus([] { InfiniFrameWindow::Register(); }); - } -#endif - - EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { - ResetOut(value, static_cast(nullptr)); - return RunExportStatus([&] { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - if (initParams == nullptr) throw std::invalid_argument("Argument 'initParams' is null."); - if (initParams->Size != static_cast(sizeof(InfiniFrameInitParams))) { - throw std::invalid_argument("InfiniFrameInitParams.Size does not match native struct size."); - } - auto instance = std::make_unique(initParams); - *value = instance.release(); - }); - } - - EXPORTED InteropStatus InfiniFrame_dtor(InfiniFrameWindow* instance) { - return RunExportStatus([&] { - if (!EnsureNotNull(instance, "instance")) throw std::invalid_argument("Argument 'instance' is null."); - std::unique_ptr guard{instance}; - }); - } - - EXPORTED InteropStatus InfiniFrame_Center(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Center(); }); } - EXPORTED InteropStatus InfiniFrame_ClearBrowserAutoFill(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->ClearBrowserAutoFill(); }); } - EXPORTED InteropStatus InfiniFrame_Close(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Close(); }); } - - EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetTransparentEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetContextMenuEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetContextMenuEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetZoomEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetZoomEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetDevToolsEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetDevToolsEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetFullScreen(InfiniFrameWindow* instance, bool* fullScreen) { - ResetOut(fullScreen, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(fullScreen, "fullScreen")) throw std::invalid_argument("Argument 'fullScreen' is null."); - window->GetFullScreen(fullScreen); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetGrantBrowserPermissions(InfiniFrameWindow* instance, bool* grant) { - ResetOut(grant, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(grant, "grant")) throw std::invalid_argument("Argument 'grant' is null."); - window->GetGrantBrowserPermissions(grant); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetUserAgent(InfiniFrameWindow* instance, AutoString* value) { - ResetOut(value, static_cast(nullptr)); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - *value = window->GetUserAgent(); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetMediaAutoplayEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetMediaAutoplayEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetFileSystemAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetFileSystemAccessEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetWebSecurityEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetWebSecurityEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetJavascriptClipboardAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetJavascriptClipboardAccessEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetMediaStreamEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetMediaStreamEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetSmoothScrollingEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetSmoothScrollingEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetMaximized(InfiniFrameWindow* instance, bool* isMaximized) { - ResetOut(isMaximized, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(isMaximized, "isMaximized")) throw std::invalid_argument("Argument 'isMaximized' is null."); - window->GetMaximized(isMaximized); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetMinimized(InfiniFrameWindow* instance, bool* isMinimized) { - ResetOut(isMinimized, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(isMinimized, "isMinimized")) throw std::invalid_argument("Argument 'isMinimized' is null."); - window->GetMinimized(isMinimized); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetIgnoreCertificateErrorsEnabled(InfiniFrameWindow* instance, bool* enabled) { - ResetOut(enabled, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); - window->GetIgnoreCertificateErrorsEnabled(enabled); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetPosition(InfiniFrameWindow* instance, int* x, int* y) { - ResetOut2(x, y, 0); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(x, "x") || !EnsureNotNull(y, "y")) throw std::invalid_argument("GetPosition out argument is null."); - window->GetPosition(x, y); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetResizable(InfiniFrameWindow* instance, bool* resizable) { - ResetOut(resizable, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(resizable, "resizable")) throw std::invalid_argument("Argument 'resizable' is null."); - window->GetResizable(resizable); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetScreenDpi(InfiniFrameWindow* instance, unsigned int* value) { - ResetOut(value, static_cast(0)); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - *value = window->GetScreenDpi(); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetSize(InfiniFrameWindow* instance, int* width, int* height) { - ResetOut2(width, height, 0); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetSize out argument is null."); - window->GetSize(width, height); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetMaxSize(InfiniFrameWindow* instance, int* width, int* height) { - ResetOut2(width, height, 0); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetMaxSize out argument is null."); - window->GetMaxSize(width, height); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetMinSize(InfiniFrameWindow* instance, int* width, int* height) { - ResetOut2(width, height, 0); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetMinSize out argument is null."); - window->GetMinSize(width, height); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetTitle(InfiniFrameWindow* instance, AutoString* value) { - ResetOut(value, static_cast(nullptr)); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - *value = window->GetTitle(); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetTopmost(InfiniFrameWindow* instance, bool* topmost) { - ResetOut(topmost, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(topmost, "topmost")) throw std::invalid_argument("Argument 'topmost' is null."); - window->GetTopmost(topmost); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetZoom(InfiniFrameWindow* instance, int* zoom) { - ResetOut(zoom, 0); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(zoom, "zoom")) throw std::invalid_argument("Argument 'zoom' is null."); - window->GetZoom(zoom); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetFocused(InfiniFrameWindow* instance, bool* isFocused) { - ResetOut(isFocused, false); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(isFocused, "isFocused")) throw std::invalid_argument("Argument 'isFocused' is null."); - window->GetFocused(isFocused); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetIconFileName(InfiniFrameWindow* instance, AutoString* value) { - ResetOut(value, static_cast(nullptr)); - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - *value = window->GetIconFileName(); - }); - } - - EXPORTED InteropStatus InfiniFrame_NavigateToString(InfiniFrameWindow* instance, const AutoString content) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(content, "content")) throw std::invalid_argument("Argument 'content' is null."); - window->NavigateToString(content); - }); - } - - EXPORTED InteropStatus InfiniFrame_NavigateToUrl(InfiniFrameWindow* instance, const AutoString url) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(url, "url")) throw std::invalid_argument("Argument 'url' is null."); - window->NavigateToUrl(url); - }); - } - - EXPORTED InteropStatus InfiniFrame_Restore(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Restore(); }); } - - EXPORTED InteropStatus InfiniFrame_SendWebMessage(InfiniFrameWindow* instance, const AutoString message) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(message, "message")) throw std::invalid_argument("Argument 'message' is null."); - window->SendWebMessage(message); - }); - } - - EXPORTED InteropStatus InfiniFrame_SetTransparentEnabled(InfiniFrameWindow* instance, const bool enabled) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetTransparentEnabled(enabled); }); } - EXPORTED InteropStatus InfiniFrame_SetContextMenuEnabled(InfiniFrameWindow* instance, const bool enabled) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetContextMenuEnabled(enabled); }); } - EXPORTED InteropStatus InfiniFrame_SetZoomEnabled(InfiniFrameWindow* instance, const bool enabled) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetZoomEnabled(enabled); }); } - EXPORTED InteropStatus InfiniFrame_SetDevToolsEnabled(InfiniFrameWindow* instance, const bool enabled) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetDevToolsEnabled(enabled); }); } - EXPORTED InteropStatus InfiniFrame_SetFullScreen(InfiniFrameWindow* instance, const bool fullScreen) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFullScreen(fullScreen); }); } - - EXPORTED InteropStatus InfiniFrame_SetIconFile(InfiniFrameWindow* instance, const AutoString filename) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(filename, "filename")) throw std::invalid_argument("Argument 'filename' is null."); - window->SetIconFile(filename); - }); - } - - EXPORTED InteropStatus InfiniFrame_SetMaximized(InfiniFrameWindow* instance, const bool maximized) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMaximized(maximized); }); } - EXPORTED InteropStatus InfiniFrame_SetMaxSize(InfiniFrameWindow* instance, const int width, const int height) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMaxSize(width, height); }); } - EXPORTED InteropStatus InfiniFrame_SetMinimized(InfiniFrameWindow* instance, const bool minimized) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMinimized(minimized); }); } - EXPORTED InteropStatus InfiniFrame_SetMinSize(InfiniFrameWindow* instance, const int width, const int height) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMinSize(width, height); }); } - EXPORTED InteropStatus InfiniFrame_SetPosition(InfiniFrameWindow* instance, const int x, const int y) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetPosition(x, y); }); } - EXPORTED InteropStatus InfiniFrame_SetResizable(InfiniFrameWindow* instance, const bool resizable) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetResizable(resizable); }); } - EXPORTED InteropStatus InfiniFrame_SetSize(InfiniFrameWindow* instance, const int width, const int height) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetSize(width, height); }); } - - EXPORTED InteropStatus InfiniFrame_SetTitle(InfiniFrameWindow* instance, const AutoString title) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(title, "title")) throw std::invalid_argument("Argument 'title' is null."); - window->SetTitle(title); - }); - } - - EXPORTED InteropStatus InfiniFrame_SetTopmost(InfiniFrameWindow* instance, const bool topmost) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetTopmost(topmost); }); } - EXPORTED InteropStatus InfiniFrame_SetZoom(InfiniFrameWindow* instance, const int zoom) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetZoom(zoom); }); } - - EXPORTED InteropStatus InfiniFrame_ShowNotification(InfiniFrameWindow* instance, const AutoString title, const AutoString body) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(title, "title") || !EnsureNotNull(body, "body")) throw std::invalid_argument("ShowNotification argument is null."); - window->ShowNotification(title, body); - }); - } - - EXPORTED InteropStatus InfiniFrame_WaitForExit(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->WaitForExit(); }); } - - EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { - return RunExportStatus([&] { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); -#ifdef _WIN32 - delete[] value; -#elif __linux__ - g_free(value); -#else - free(value); -#endif - }); - } - - EXPORTED InteropStatus InfiniFrame_FreeStringArray(AutoString* values, const int count) { - return RunExportStatus([&] { - if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); - if (count < 0) throw std::invalid_argument("Argument 'count' must be >= 0."); - for (int i = 0; i < count; ++i) { - if (values[i] != nullptr) { - InfiniFrame_FreeString(values[i]); - } - } -#ifdef _WIN32 - delete[] values; -#elif __linux__ - delete[] values; -#else - free(values); -#endif - }); - } - - EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, AutoString* filters, const int filterCount, int* resultCount, AutoString** values) { - ResetOut(resultCount, 0); - ResetOut(values, static_cast(nullptr)); - return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); - if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); - if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); - *values = window->GetDialog()->ShowOpenFile(title, defaultPath, multiSelect, filters, filterCount, resultCount); - }); - } - - EXPORTED InteropStatus InfiniFrame_ShowOpenFolder(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, int* resultCount, AutoString** values) { - ResetOut(resultCount, 0); - ResetOut(values, static_cast(nullptr)); - return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); - if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); - *values = window->GetDialog()->ShowOpenFolder(title, defaultPath, multiSelect, resultCount); - }); - } - - EXPORTED InteropStatus InfiniFrame_ShowSaveFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, AutoString* filters, const int filterCount, const AutoString defaultFileName, AutoString* value) { - ResetOut(value, static_cast(nullptr)); - return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); - *value = window->GetDialog()->ShowSaveFile(title, defaultPath, filters, filterCount, defaultFileName); - }); - } - - EXPORTED InteropStatus InfiniFrame_ShowMessage(InfiniFrameWindow* inst, const AutoString title, const AutoString text, const DialogButtons buttons, const DialogIcon icon, DialogResult* value) { - ResetOut(value, DialogResult::Cancel); - return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - *value = window->GetDialog()->ShowMessage(title, text, buttons, icon); - }); - } - - EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(scheme, "scheme")) throw std::invalid_argument("Argument 'scheme' is null."); - window->AddCustomSchemeName(scheme); - }); - } - - EXPORTED InteropStatus InfiniFrame_GetAllMonitors(InfiniFrameWindow* instance, const GetAllMonitorsCallback callback) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (callback == nullptr) throw std::invalid_argument("Argument 'callback' is null."); - window->GetAllMonitors(callback); - }); - } - - EXPORTED InteropStatus InfiniFrame_SetClosingCallback(InfiniFrameWindow* instance, const ClosingCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetClosingCallback(callback); }); } - EXPORTED InteropStatus InfiniFrame_setClosedClosedCallback(InfiniFrameWindow* instance, const ClosedCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetClosedCallback(callback); }); } - EXPORTED InteropStatus InfiniFrame_SetFocusInCallback(InfiniFrameWindow* instance, const FocusInCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFocusInCallback(callback); }); } - EXPORTED InteropStatus InfiniFrame_SetFocusOutCallback(InfiniFrameWindow* instance, const FocusOutCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFocusOutCallback(callback); }); } - EXPORTED InteropStatus InfiniFrame_SetMovedCallback(InfiniFrameWindow* instance, const MovedCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMovedCallback(callback); }); } - EXPORTED InteropStatus InfiniFrame_SetResizedCallback(InfiniFrameWindow* instance, const ResizedCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetResizedCallback(callback); }); } - - EXPORTED InteropStatus InfiniFrame_Invoke(InfiniFrameWindow* instance, const ACTION callback) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (callback == nullptr) throw std::invalid_argument("Argument 'callback' is null."); - window->Invoke(callback); - }); - } - - EXPORTED InteropStatus InfiniFrame_SetFocused(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->SetFocused(); }); } - - EXPORTED InteropStatus InfiniFrame_GetLastErrorMessage(AutoString* value) { - ResetOut(value, static_cast(nullptr)); - return RunExportStatus([&] { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - *value = GetLastErrorMessageCopy(); - }); - } -} diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp new file mode 100644 index 000000000..58f3a7906 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp @@ -0,0 +1,41 @@ +#include "Exports/Exports.Shared.h" + +extern "C" { +EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, AutoString* filters, const int filterCount, int* resultCount, AutoString** values) { + ResetOut(resultCount, 0); + ResetOut(values, static_cast(nullptr)); + return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); + if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); + *values = window->GetDialog()->ShowOpenFile(title, defaultPath, multiSelect, filters, filterCount, resultCount); + }); +} + +EXPORTED InteropStatus InfiniFrame_ShowOpenFolder(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, int* resultCount, AutoString** values) { + ResetOut(resultCount, 0); + ResetOut(values, static_cast(nullptr)); + return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); + if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + *values = window->GetDialog()->ShowOpenFolder(title, defaultPath, multiSelect, resultCount); + }); +} + +EXPORTED InteropStatus InfiniFrame_ShowSaveFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, AutoString* filters, const int filterCount, const AutoString defaultFileName, AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); + *value = window->GetDialog()->ShowSaveFile(title, defaultPath, filters, filterCount, defaultFileName); + }); +} + +EXPORTED InteropStatus InfiniFrame_ShowMessage(InfiniFrameWindow* inst, const AutoString title, const AutoString text, const DialogButtons buttons, const DialogIcon icon, DialogResult* value) { + ResetOut(value, DialogResult::Cancel); + return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetDialog()->ShowMessage(title, text, buttons, icon); + }); +} +} diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp new file mode 100644 index 000000000..fdbebd787 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp @@ -0,0 +1,48 @@ +#include "Exports/Exports.Shared.h" + +extern "C" { +EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(scheme, "scheme")) throw std::invalid_argument("Argument 'scheme' is null."); + window->AddCustomSchemeName(scheme); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetAllMonitors(InfiniFrameWindow* instance, const GetAllMonitorsCallback callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (callback == nullptr) throw std::invalid_argument("Argument 'callback' is null."); + window->GetAllMonitors(callback); + }); +} + +EXPORTED InteropStatus InfiniFrame_SetClosingCallback(InfiniFrameWindow* instance, const ClosingCallback callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetClosingCallback(callback); }); +} + +EXPORTED InteropStatus InfiniFrame_setClosedClosedCallback(InfiniFrameWindow* instance, const ClosedCallback callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetClosedCallback(callback); }); +} + +EXPORTED InteropStatus InfiniFrame_SetFocusInCallback(InfiniFrameWindow* instance, const FocusInCallback callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFocusInCallback(callback); }); +} + +EXPORTED InteropStatus InfiniFrame_SetFocusOutCallback(InfiniFrameWindow* instance, const FocusOutCallback callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFocusOutCallback(callback); }); +} + +EXPORTED InteropStatus InfiniFrame_SetMovedCallback(InfiniFrameWindow* instance, const MovedCallback callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMovedCallback(callback); }); +} + +EXPORTED InteropStatus InfiniFrame_SetResizedCallback(InfiniFrameWindow* instance, const ResizedCallback callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetResizedCallback(callback); }); +} + +EXPORTED InteropStatus InfiniFrame_Invoke(InfiniFrameWindow* instance, const ACTION callback) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (callback == nullptr) throw std::invalid_argument("Argument 'callback' is null."); + window->Invoke(callback); + }); +} +} diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp new file mode 100644 index 000000000..e66c096b7 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp @@ -0,0 +1,31 @@ +#include "Exports/Exports.Shared.h" + +extern "C" { +EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { + ResetOut(value, static_cast(nullptr)); + return RunExportStatus([&] { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (initParams == nullptr) throw std::invalid_argument("Argument 'initParams' is null."); + if (initParams->Size != static_cast(sizeof(InfiniFrameInitParams))) { + throw std::invalid_argument("InfiniFrameInitParams.Size does not match native struct size."); + } + auto instance = std::make_unique(initParams); + *value = instance.release(); + }); +} + +EXPORTED InteropStatus InfiniFrame_dtor(InfiniFrameWindow* instance) { + return RunExportStatus([&] { + if (!EnsureNotNull(instance, "instance")) throw std::invalid_argument("Argument 'instance' is null."); + std::unique_ptr guard{instance}; + }); +} + +EXPORTED InteropStatus InfiniFrame_Close(InfiniFrameWindow* instance) { + return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Close(); }); +} + +EXPORTED InteropStatus InfiniFrame_WaitForExit(InfiniFrameWindow* instance) { + return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->WaitForExit(); }); +} +} diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp new file mode 100644 index 000000000..17a8fafab --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp @@ -0,0 +1,43 @@ +#include "Exports/Exports.Shared.h" + +extern "C" { +EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { + return RunExportStatus([&] { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); +#ifdef _WIN32 + delete[] value; +#elif __linux__ + g_free(value); +#else + free(value); +#endif + }); +} + +EXPORTED InteropStatus InfiniFrame_FreeStringArray(AutoString* values, const int count) { + return RunExportStatus([&] { + if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + if (count < 0) throw std::invalid_argument("Argument 'count' must be >= 0."); + for (int i = 0; i < count; ++i) { + if (values[i] != nullptr) { + InfiniFrame_FreeString(values[i]); + } + } +#ifdef _WIN32 + delete[] values; +#elif __linux__ + delete[] values; +#else + free(values); +#endif + }); +} + +EXPORTED InteropStatus InfiniFrame_GetLastErrorMessage(AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunExportStatus([&] { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = GetLastErrorMessageCopy(); + }); +} +} diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp new file mode 100644 index 000000000..a1c4a6070 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp @@ -0,0 +1,39 @@ +#include "Exports/Exports.Shared.h" + +extern "C" { +#ifdef _WIN32 +EXPORTED InteropStatus InfiniFrame_register_win32(const HINSTANCE hInstance) { + return RunExportStatus([&] { + if (hInstance == nullptr) throw std::invalid_argument("Argument 'hInstance' is null."); + InfiniFrameWindow::Register(hInstance); + }); +} + +EXPORTED InteropStatus InfiniFrame_getHwnd_win32(InfiniFrameWindow* instance, HWND* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->getHwnd(); + }); +} + +EXPORTED InteropStatus InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindow*, const AutoString webView2RuntimePath) { + return RunExportStatus([&] { + if (!EnsureNotNull(webView2RuntimePath, "webView2RuntimePath")) throw std::invalid_argument("Argument 'webView2RuntimePath' is null."); + InfiniFrameWindow::SetWebView2RuntimePath(webView2RuntimePath); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetNotificationsEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetNotificationsEnabled(enabled); + }); +} +#elif __APPLE__ +EXPORTED InteropStatus InfiniFrame_register_mac() { + return RunExportStatus([] { InfiniFrameWindow::Register(); }); +} +#endif +} diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Shared.h b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Shared.h new file mode 100644 index 000000000..fa1d75ee5 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Shared.h @@ -0,0 +1,28 @@ +#pragma once + +#ifndef INFINIFRAME_EXPORTS_SHARED_H +#define INFINIFRAME_EXPORTS_SHARED_H + +#include "../Core/InfiniFrame.h" +#include "ExportGuards.h" + +#ifdef __linux__ +#include +#endif + +#ifdef _WIN32 +#define EXPORTED __declspec(dllexport) +#else +#define EXPORTED +#endif + +using infiniframe::exports::EnsureNotNull; +using infiniframe::exports::GetLastErrorMessageCopy; +using infiniframe::exports::ResetOut; +using infiniframe::exports::ResetOut2; +using infiniframe::exports::RunExportStatus; +using infiniframe::exports::RunReturnExport; +using infiniframe::exports::RunWindowExportStatus; +using infiniframe::exports::RunWindowReturnExport; + +#endif // INFINIFRAME_EXPORTS_SHARED_H diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp new file mode 100644 index 000000000..7548826c9 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp @@ -0,0 +1,117 @@ +#include "Exports/Exports.Shared.h" + +extern "C" { +EXPORTED InteropStatus InfiniFrame_Center(InfiniFrameWindow* instance) { + return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Center(); }); +} + +EXPORTED InteropStatus InfiniFrame_ClearBrowserAutoFill(InfiniFrameWindow* instance) { + return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->ClearBrowserAutoFill(); }); +} + +EXPORTED InteropStatus InfiniFrame_NavigateToString(InfiniFrameWindow* instance, const AutoString content) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(content, "content")) throw std::invalid_argument("Argument 'content' is null."); + window->NavigateToString(content); + }); +} + +EXPORTED InteropStatus InfiniFrame_NavigateToUrl(InfiniFrameWindow* instance, const AutoString url) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(url, "url")) throw std::invalid_argument("Argument 'url' is null."); + window->NavigateToUrl(url); + }); +} + +EXPORTED InteropStatus InfiniFrame_Restore(InfiniFrameWindow* instance) { + return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Restore(); }); +} + +EXPORTED InteropStatus InfiniFrame_SendWebMessage(InfiniFrameWindow* instance, const AutoString message) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(message, "message")) throw std::invalid_argument("Argument 'message' is null."); + window->SendWebMessage(message); + }); +} + +EXPORTED InteropStatus InfiniFrame_SetTransparentEnabled(InfiniFrameWindow* instance, const bool enabled) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetTransparentEnabled(enabled); }); +} + +EXPORTED InteropStatus InfiniFrame_SetContextMenuEnabled(InfiniFrameWindow* instance, const bool enabled) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetContextMenuEnabled(enabled); }); +} + +EXPORTED InteropStatus InfiniFrame_SetZoomEnabled(InfiniFrameWindow* instance, const bool enabled) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetZoomEnabled(enabled); }); +} + +EXPORTED InteropStatus InfiniFrame_SetDevToolsEnabled(InfiniFrameWindow* instance, const bool enabled) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetDevToolsEnabled(enabled); }); +} + +EXPORTED InteropStatus InfiniFrame_SetFullScreen(InfiniFrameWindow* instance, const bool fullScreen) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetFullScreen(fullScreen); }); +} + +EXPORTED InteropStatus InfiniFrame_SetIconFile(InfiniFrameWindow* instance, const AutoString filename) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(filename, "filename")) throw std::invalid_argument("Argument 'filename' is null."); + window->SetIconFile(filename); + }); +} + +EXPORTED InteropStatus InfiniFrame_SetMaximized(InfiniFrameWindow* instance, const bool maximized) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMaximized(maximized); }); +} + +EXPORTED InteropStatus InfiniFrame_SetMaxSize(InfiniFrameWindow* instance, const int width, const int height) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMaxSize(width, height); }); +} + +EXPORTED InteropStatus InfiniFrame_SetMinimized(InfiniFrameWindow* instance, const bool minimized) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMinimized(minimized); }); +} + +EXPORTED InteropStatus InfiniFrame_SetMinSize(InfiniFrameWindow* instance, const int width, const int height) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetMinSize(width, height); }); +} + +EXPORTED InteropStatus InfiniFrame_SetPosition(InfiniFrameWindow* instance, const int x, const int y) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetPosition(x, y); }); +} + +EXPORTED InteropStatus InfiniFrame_SetResizable(InfiniFrameWindow* instance, const bool resizable) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetResizable(resizable); }); +} + +EXPORTED InteropStatus InfiniFrame_SetSize(InfiniFrameWindow* instance, const int width, const int height) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetSize(width, height); }); +} + +EXPORTED InteropStatus InfiniFrame_SetTitle(InfiniFrameWindow* instance, const AutoString title) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(title, "title")) throw std::invalid_argument("Argument 'title' is null."); + window->SetTitle(title); + }); +} + +EXPORTED InteropStatus InfiniFrame_SetTopmost(InfiniFrameWindow* instance, const bool topmost) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetTopmost(topmost); }); +} + +EXPORTED InteropStatus InfiniFrame_SetZoom(InfiniFrameWindow* instance, const int zoom) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetZoom(zoom); }); +} + +EXPORTED InteropStatus InfiniFrame_ShowNotification(InfiniFrameWindow* instance, const AutoString title, const AutoString body) { + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(title, "title") || !EnsureNotNull(body, "body")) throw std::invalid_argument("ShowNotification argument is null."); + window->ShowNotification(title, body); + }); +} + +EXPORTED InteropStatus InfiniFrame_SetFocused(InfiniFrameWindow* instance) { + return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->SetFocused(); }); +} +} diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp new file mode 100644 index 000000000..a4d81e8fc --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp @@ -0,0 +1,219 @@ +#include "Exports/Exports.Shared.h" + +extern "C" { +EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetTransparentEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetContextMenuEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetContextMenuEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetZoomEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetZoomEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetDevToolsEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetDevToolsEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetFullScreen(InfiniFrameWindow* instance, bool* fullScreen) { + ResetOut(fullScreen, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(fullScreen, "fullScreen")) throw std::invalid_argument("Argument 'fullScreen' is null."); + window->GetFullScreen(fullScreen); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetGrantBrowserPermissions(InfiniFrameWindow* instance, bool* grant) { + ResetOut(grant, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(grant, "grant")) throw std::invalid_argument("Argument 'grant' is null."); + window->GetGrantBrowserPermissions(grant); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetUserAgent(InfiniFrameWindow* instance, AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetUserAgent(); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetMediaAutoplayEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetMediaAutoplayEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetFileSystemAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetFileSystemAccessEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetWebSecurityEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetWebSecurityEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetJavascriptClipboardAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetJavascriptClipboardAccessEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetMediaStreamEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetMediaStreamEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetSmoothScrollingEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetSmoothScrollingEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetMaximized(InfiniFrameWindow* instance, bool* isMaximized) { + ResetOut(isMaximized, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(isMaximized, "isMaximized")) throw std::invalid_argument("Argument 'isMaximized' is null."); + window->GetMaximized(isMaximized); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetMinimized(InfiniFrameWindow* instance, bool* isMinimized) { + ResetOut(isMinimized, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(isMinimized, "isMinimized")) throw std::invalid_argument("Argument 'isMinimized' is null."); + window->GetMinimized(isMinimized); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetIgnoreCertificateErrorsEnabled(InfiniFrameWindow* instance, bool* enabled) { + ResetOut(enabled, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + window->GetIgnoreCertificateErrorsEnabled(enabled); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetPosition(InfiniFrameWindow* instance, int* x, int* y) { + ResetOut2(x, y, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(x, "x") || !EnsureNotNull(y, "y")) throw std::invalid_argument("GetPosition out argument is null."); + window->GetPosition(x, y); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetResizable(InfiniFrameWindow* instance, bool* resizable) { + ResetOut(resizable, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(resizable, "resizable")) throw std::invalid_argument("Argument 'resizable' is null."); + window->GetResizable(resizable); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetScreenDpi(InfiniFrameWindow* instance, unsigned int* value) { + ResetOut(value, static_cast(0)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetScreenDpi(); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetSize(InfiniFrameWindow* instance, int* width, int* height) { + ResetOut2(width, height, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetSize out argument is null."); + window->GetSize(width, height); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetMaxSize(InfiniFrameWindow* instance, int* width, int* height) { + ResetOut2(width, height, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetMaxSize out argument is null."); + window->GetMaxSize(width, height); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetMinSize(InfiniFrameWindow* instance, int* width, int* height) { + ResetOut2(width, height, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetMinSize out argument is null."); + window->GetMinSize(width, height); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetTitle(InfiniFrameWindow* instance, AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetTitle(); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetTopmost(InfiniFrameWindow* instance, bool* topmost) { + ResetOut(topmost, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(topmost, "topmost")) throw std::invalid_argument("Argument 'topmost' is null."); + window->GetTopmost(topmost); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetZoom(InfiniFrameWindow* instance, int* zoom) { + ResetOut(zoom, 0); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(zoom, "zoom")) throw std::invalid_argument("Argument 'zoom' is null."); + window->GetZoom(zoom); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetFocused(InfiniFrameWindow* instance, bool* isFocused) { + ResetOut(isFocused, false); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(isFocused, "isFocused")) throw std::invalid_argument("Argument 'isFocused' is null."); + window->GetFocused(isFocused); + }); +} + +EXPORTED InteropStatus InfiniFrame_GetIconFileName(InfiniFrameWindow* instance, AutoString* value) { + ResetOut(value, static_cast(nullptr)); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { + if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + *value = window->GetIconFileName(); + }); +} +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h new file mode 100644 index 000000000..157498f54 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h @@ -0,0 +1,40 @@ +#pragma once + +#ifndef INFINIFRAME_PLATFORM_LINUX_WINDOW_GTK_INTERNAL_H +#define INFINIFRAME_PLATFORM_LINUX_WINDOW_GTK_INTERNAL_H + +#include +#include + +#include +#include + +#include "Core/InfiniFrameWindow.h" +#include "Core/InfiniFrameWindowImpl.h" + +struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { + GtkWidget* _window = nullptr; + GtkWidget* _webview = nullptr; + + std::string _temporaryFilesPath; + + bool _isFullScreen = false; + double _zoom = 100.0; + int _minWidth = 0; + int _minHeight = 0; + int _maxWidth = INT_MAX; + int _maxHeight = INT_MAX; + + GdkGeometry _hints = {}; + + int _lastLeft = 0; + int _lastTop = 0; + int _lastWidth = 0; + int _lastHeight = 0; + + void set_webkit_settings(); + void set_webkit_customsettings(WebKitSettings* settings); + void AddCustomSchemeHandlers(); +}; + +#endif // INFINIFRAME_PLATFORM_LINUX_WINDOW_GTK_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp index 0dc0a7de8..8d6f88ac5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp @@ -1,8 +1,8 @@ #ifdef __linux__ #include "Core/InfiniFrameWindow.h" #include "Core/InfiniFrameDialog.h" -#include "Core/InfiniFrameWindowImpl.h" #include "Utils/Common.h" +#include "Window.Gtk.Internal.h" #include #include #include @@ -56,35 +56,6 @@ void on_webview_process_terminated( ); void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data); -// --------------------------------------------------------------------------------------------------------------------- -// Platform Impl -// --------------------------------------------------------------------------------------------------------------------- - -struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { - GtkWidget* _window = nullptr; - GtkWidget* _webview = nullptr; - - std::string _temporaryFilesPath; - - bool _isFullScreen = false; - double _zoom = 100.0; - int _minWidth = 0; - int _minHeight = 0; - int _maxWidth = INT_MAX; - int _maxHeight = INT_MAX; - - GdkGeometry _hints = {}; - - int _lastLeft = 0; - int _lastTop = 0; - int _lastWidth = 0; - int _lastHeight = 0; - - void set_webkit_settings(); - void set_webkit_customsettings(WebKitSettings* settings); - void AddCustomSchemeHandlers(); -}; - // --------------------------------------------------------------------------------------------------------------------- // Static signal handlers and helpers // --------------------------------------------------------------------------------------------------------------------- @@ -161,46 +132,6 @@ static void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpo free(contentType); } -static std::string escapeJsonString(std::string_view input) { - std::string result; - result.reserve(input.size() + 2); - - for (char c : input) { - switch (c) { - case '"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - default: - if (static_cast(c) < 0x20) { - std::format_to(std::back_inserter(result), "\\u{:04x}", static_cast(c)); - } - else { - result += c; - } - } - } - - return result; -} - static bool linux_webview_diagnostics_enabled() { const char* value = g_getenv("INFINIFRAME_LINUX_WEBVIEW_DIAGNOSTICS"); return value != nullptr && value[0] != '\0' && g_strcmp0(value, "0") != 0; @@ -557,447 +488,6 @@ InfiniFrameWindow::~InfiniFrameWindow() { // Window Operations // --------------------------------------------------------------------------------------------------------------------- -void InfiniFrameWindow::Center() { - gint windowWidth, windowHeight; - gtk_window_get_size(GTK_WINDOW(m_impl->_window), &windowWidth, &windowHeight); - - GdkRectangle screen = {0}; - - GdkDisplay* d = gdk_display_get_default(); - if (d == nullptr) { - GtkWidget* dialog = gtk_message_dialog_new( - nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "gdk_display_get_default() returned NULL" - ); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - return; - } - - GdkMonitor* m = gdk_display_get_primary_monitor(d); - if (m == nullptr) { - m = gdk_display_get_monitor(d, 0); - if (m == nullptr) { - GtkWidget* dialog = gtk_message_dialog_new( - nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "gdk_display_get_primary_monitor() returned NULL" - ); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - return; - } - } - - gdk_monitor_get_geometry(m, &screen); - - gtk_window_move( - GTK_WINDOW(m_impl->_window), - (screen.width - windowWidth) / 2, - (screen.height - windowHeight) / 2 - ); -} - -void InfiniFrameWindow::ClearBrowserAutoFill() { - // TODO -} - -void InfiniFrameWindow::Close() { - gtk_window_close(GTK_WINDOW(m_impl->_window)); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Get Properties -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::GetTransparentEnabled(bool* enabled) const { - *enabled = m_impl->_transparentEnabled; -} - -void InfiniFrameWindow::GetContextMenuEnabled(bool* enabled) const { - *enabled = m_impl->_contextMenuEnabled; -} - -void InfiniFrameWindow::GetZoomEnabled(bool* enabled) const { - *enabled = m_impl->_zoomEnabled; -} - -void InfiniFrameWindow::GetDevToolsEnabled(bool* enabled) const { - WebKitSettings* settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(m_impl->_webview)); - *enabled = webkit_settings_get_enable_developer_extras(settings); -} - -void InfiniFrameWindow::GetFullScreen(bool* fullScreen) const { - *fullScreen = m_impl->_isFullScreen; -} - -void InfiniFrameWindow::GetGrantBrowserPermissions(bool* grant) const { - *grant = m_impl->_grantBrowserPermissions; -} - -AutoString InfiniFrameWindow::GetUserAgent() const { - return AllocateStringCopy(m_impl->_userAgent); -} - -void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const { - *enabled = m_impl->_mediaAutoplayEnabled; -} - -void InfiniFrameWindow::GetFileSystemAccessEnabled(bool* enabled) const { - *enabled = m_impl->_fileSystemAccessEnabled; -} - -void InfiniFrameWindow::GetWebSecurityEnabled(bool* enabled) const { - *enabled = m_impl->_webSecurityEnabled; -} - -void InfiniFrameWindow::GetJavascriptClipboardAccessEnabled(bool* enabled) const { - *enabled = m_impl->_javascriptClipboardAccessEnabled; -} - -void InfiniFrameWindow::GetMediaStreamEnabled(bool* enabled) const { - *enabled = m_impl->_mediaStreamEnabled; -} - -void InfiniFrameWindow::GetSmoothScrollingEnabled(bool* enabled) const { - *enabled = m_impl->_smoothScrollingEnabled; -} - -void InfiniFrameWindow::GetIgnoreCertificateErrorsEnabled(bool* enabled) const { - *enabled = m_impl->_ignoreCertificateErrorsEnabled; -} - -void InfiniFrameWindow::GetMaximized(bool* isMaximized) const { - GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(m_impl->_window)); - GdkWindowState flags = gdk_window_get_state(gdk_window); - *isMaximized = flags & GDK_WINDOW_STATE_MAXIMIZED; -} - -void InfiniFrameWindow::GetMinimized(bool* isMinimized) const { - GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(m_impl->_window)); - GdkWindowState flags = gdk_window_get_state(gdk_window); - *isMinimized = flags & GDK_WINDOW_STATE_ICONIFIED; -} - -void InfiniFrameWindow::GetPosition(int* x, int* y) const { - gtk_window_get_position(GTK_WINDOW(m_impl->_window), x, y); -} - -void InfiniFrameWindow::GetResizable(bool* resizable) const { - *resizable = gtk_window_get_resizable(GTK_WINDOW(m_impl->_window)); -} - -unsigned int InfiniFrameWindow::GetScreenDpi() const { - GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(m_impl->_window)); - gdouble dpi = gdk_screen_get_resolution(screen); - if (dpi < 0) - return 96; - else - return static_cast(dpi); -} - -void InfiniFrameWindow::GetSize(int* width, int* height) const { - gtk_window_get_size(GTK_WINDOW(m_impl->_window), width, height); -} - -void InfiniFrameWindow::GetMaxSize(int* width, int* height) const { - if (width) - *width = m_impl->_maxWidth; - if (height) - *height = m_impl->_maxHeight; -} - -void InfiniFrameWindow::GetMinSize(int* width, int* height) const { - if (width) - *width = m_impl->_minWidth; - if (height) - *height = m_impl->_minHeight; -} - -AutoString InfiniFrameWindow::GetTitle() const { - const char* title = gtk_window_get_title(GTK_WINDOW(m_impl->_window)); - return g_strdup(title ? title : ""); -} - -void InfiniFrameWindow::GetTopmost(bool* topmost) const { - GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(m_impl->_window)); - GdkWindowState flags = gdk_window_get_state(gdk_window); - *topmost = flags & GDK_WINDOW_STATE_ABOVE; -} - -void InfiniFrameWindow::GetZoom(int* zoom) const { - double rawValue = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(m_impl->_webview)); - rawValue = (rawValue * 100.0) + 0.5; - *zoom = static_cast(rawValue); -} - -void InfiniFrameWindow::GetFocused(bool* isFocused) const { - *isFocused = gtk_window_is_active(GTK_WINDOW(m_impl->_window)); -} - -AutoString InfiniFrameWindow::GetIconFileName() const { - return AllocateStringCopy(m_impl->_iconFileName); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Navigation -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::NavigateToString(const AutoString content) { - webkit_web_view_load_html(WEBKIT_WEB_VIEW(m_impl->_webview), content, nullptr); -} - -void InfiniFrameWindow::NavigateToUrl(const AutoString url) { - webkit_web_view_load_uri(WEBKIT_WEB_VIEW(m_impl->_webview), url); -} - -void InfiniFrameWindow::Restore() { - gtk_window_present(GTK_WINDOW(m_impl->_window)); -} - -static void webview_eval_finished(GObject* object, GAsyncResult* result, gpointer) { - GError* error = nullptr; - webkit_web_view_evaluate_javascript_finish(WEBKIT_WEB_VIEW(object), result, &error); - if (error) { - g_warning("JavaScript evaluation failed: %s", error->message); - g_error_free(error); - } -} - -void InfiniFrameWindow::SendWebMessage(const AutoString message) { - std::string escaped = escapeJsonString(message ? message : ""); - - std::string js; - js.append("__dispatchMessageCallback(\""); - js.append(escaped); - js.append("\")"); - - webkit_web_view_evaluate_javascript( - WEBKIT_WEB_VIEW(m_impl->_webview), - js.c_str(), - -1, - nullptr, - nullptr, - nullptr, - webview_eval_finished, - nullptr - ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Set Properties -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::SetContextMenuEnabled(const bool enabled) { - m_impl->_contextMenuEnabled = enabled; -} - -void InfiniFrameWindow::SetZoomEnabled(bool enabled) { - // Not implemented on Linux -} - -void InfiniFrameWindow::SetDevToolsEnabled(const bool enabled) { - m_impl->_devToolsEnabled = enabled; - WebKitSettings* settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(m_impl->_webview)); - webkit_settings_set_enable_developer_extras(settings, m_impl->_devToolsEnabled); -} - -void InfiniFrameWindow::SetFullScreen(const bool fullScreen) { - if (fullScreen) - gtk_window_fullscreen(GTK_WINDOW(m_impl->_window)); - else - gtk_window_unfullscreen(GTK_WINDOW(m_impl->_window)); - - m_impl->_isFullScreen = fullScreen; -} - -void InfiniFrameWindow::SetIconFile(const AutoString filename) { - gtk_window_set_icon_from_file(GTK_WINDOW(m_impl->_window), filename, nullptr); - m_impl->_iconFileName = filename ? filename : ""; -} - -void InfiniFrameWindow::SetMinimized(const bool minimized) { - if (minimized) - gtk_window_iconify(GTK_WINDOW(m_impl->_window)); - else - gtk_window_deiconify(GTK_WINDOW(m_impl->_window)); -} - -void InfiniFrameWindow::SetMaximized(const bool maximized) { - if (maximized) - gtk_window_maximize(GTK_WINDOW(m_impl->_window)); - else - gtk_window_unmaximize(GTK_WINDOW(m_impl->_window)); -} - -void InfiniFrameWindow::SetPosition(const int x, const int y) { - gtk_window_move(GTK_WINDOW(m_impl->_window), x, y); -} - -void InfiniFrameWindow::SetResizable(const bool resizable) { - gtk_window_set_resizable(GTK_WINDOW(m_impl->_window), resizable); -} - -void InfiniFrameWindow::SetMinSize(const int width, const int height) { - m_impl->_minWidth = width; - m_impl->_minHeight = height; - m_impl->_hints.min_width = width; - m_impl->_hints.min_height = height; - - gtk_window_set_geometry_hints( - GTK_WINDOW(m_impl->_window), - nullptr, - &m_impl->_hints, - (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE) - ); -} - -void InfiniFrameWindow::SetMaxSize(const int width, const int height) { - m_impl->_maxWidth = width; - m_impl->_maxHeight = height; - m_impl->_hints.max_width = width; - m_impl->_hints.max_height = height; - - gtk_window_set_geometry_hints( - GTK_WINDOW(m_impl->_window), - nullptr, - &m_impl->_hints, - (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE) - ); -} - -void InfiniFrameWindow::SetSize(const int width, const int height) { - gtk_window_resize(GTK_WINDOW(m_impl->_window), width, height); -} - -void InfiniFrameWindow::SetTitle(const AutoString title) { - gtk_window_set_title(GTK_WINDOW(m_impl->_window), title); -} - -void InfiniFrameWindow::SetTopmost(const bool topmost) { - gtk_window_set_keep_above(GTK_WINDOW(m_impl->_window), topmost); -} - -void InfiniFrameWindow::SetZoom(const int zoom) { - double newZoom = zoom / 100.0; - webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(m_impl->_webview), newZoom); -} - -void InfiniFrameWindow::SetFocused() { - gtk_window_present(GTK_WINDOW(m_impl->_window)); -} - -void InfiniFrameWindow::SetTransparentEnabled(const bool enabled) { - m_impl->_transparentEnabled = enabled; - - gtk_window_set_decorated(GTK_WINDOW(m_impl->_window), !enabled); - - GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(m_impl->_window)); - GdkVisual* rgba_visual = gdk_screen_get_rgba_visual(screen); - if (rgba_visual) { - gtk_widget_set_visual(GTK_WIDGET(m_impl->_window), rgba_visual); - gtk_widget_set_app_paintable(GTK_WIDGET(m_impl->_window), true); - - GdkRGBA color; - webkit_web_view_get_background_color(WEBKIT_WEB_VIEW(m_impl->_webview), &color); - color.alpha = enabled ? 0 : 1; - webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(m_impl->_webview), &color); - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Notifications / Event loop -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::ShowNotification(const AutoString title, const AutoString message) { - NotifyNotification* notification = notify_notification_new(title, message, nullptr); - notify_notification_set_icon_from_pixbuf(notification, gtk_window_get_icon(GTK_WINDOW(m_impl->_window))); - notify_notification_show(notification, nullptr); - g_object_unref(G_OBJECT(notification)); -} - -void InfiniFrameWindow::WaitForExit() { - g_signal_connect( - G_OBJECT(m_impl->_window), "destroy", - G_CALLBACK( - +[](GtkWidget*, gpointer) { - gtk_main_quit(); - } - ), - nullptr - ); - gtk_main(); -} - -void InfiniFrameWindow::CloseWebView() { - // Not implemented on Linux -} - -// --------------------------------------------------------------------------------------------------------------------- -// Callbacks -// --------------------------------------------------------------------------------------------------------------------- - -InfiniFrameDialog* InfiniFrameWindow::GetDialog() const { - return m_impl->_dialog.get(); -} - -void InfiniFrameWindow::AddCustomSchemeName(const AutoStringConst scheme) { - if (scheme) - m_impl->_customSchemeNames.emplace_back(scheme); -} - -void InfiniFrameWindow::GetAllMonitors(const GetAllMonitorsCallback callback) const { - if (callback) { - GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(m_impl->_window)); - GdkDisplay* display = gdk_screen_get_display(screen); - int n = gdk_display_get_n_monitors(display); - for (int i = 0; i < n; i++) { - GdkMonitor* monitor = gdk_display_get_monitor(display, i); - Monitor props = {}; - gdk_monitor_get_geometry(monitor, (GdkRectangle*)&props.monitor); - gdk_monitor_get_workarea(monitor, (GdkRectangle*)&props.work); - props.scale = gdk_monitor_get_scale_factor(monitor); - if (!callback(&props)) - break; - } - } -} - -void InfiniFrameWindow::SetClosingCallback(const ClosingCallback callback) { - m_impl->_closingCallback = callback; -} - -void InfiniFrameWindow::SetClosedCallback(const ClosedCallback callback) { - m_impl->_closedCallback = callback; -} - -void InfiniFrameWindow::SetFocusInCallback(const FocusInCallback callback) { - m_impl->_focusInCallback = callback; -} - -void InfiniFrameWindow::SetFocusOutCallback(const FocusOutCallback callback) { - m_impl->_focusOutCallback = callback; -} - -void InfiniFrameWindow::SetMovedCallback(const MovedCallback callback) { - m_impl->_movedCallback = callback; -} - -void InfiniFrameWindow::SetResizedCallback(const ResizedCallback callback) { - m_impl->_resizedCallback = callback; -} - -void InfiniFrameWindow::SetMaximizedCallback(const MaximizedCallback callback) { - m_impl->_maximizedCallback = callback; -} - -void InfiniFrameWindow::SetRestoredCallback(const RestoredCallback callback) { - m_impl->_restoredCallback = callback; -} - -void InfiniFrameWindow::SetMinimizedCallback(const MinimizedCallback callback) { - m_impl->_minimizedCallback = callback; -} - void InfiniFrameWindow::Invoke(const ACTION callback) { InvokeWaitInfo waitInfo = {}; waitInfo.callback = callback; @@ -1011,52 +501,6 @@ void InfiniFrameWindow::Invoke(const ACTION callback) { ); } -[[nodiscard]] bool InfiniFrameWindow::InvokeClose() const noexcept { - if (m_impl->_closingCallback) - return m_impl->_closingCallback(); - return false; -} - -void InfiniFrameWindow::InvokeClosed() const noexcept { - if (m_impl->_closedCallback) - m_impl->_closedCallback(); -} - -void InfiniFrameWindow::InvokeFocusIn() const noexcept { - if (m_impl->_focusInCallback) - m_impl->_focusInCallback(); -} - -void InfiniFrameWindow::InvokeFocusOut() const noexcept { - if (m_impl->_focusOutCallback) - m_impl->_focusOutCallback(); -} - -void InfiniFrameWindow::InvokeMove(int x, int y) const noexcept { - if (m_impl->_movedCallback) - m_impl->_movedCallback(x, y); -} - -void InfiniFrameWindow::InvokeResize(int width, int height) const noexcept { - if (m_impl->_resizedCallback) - m_impl->_resizedCallback(width, height); -} - -void InfiniFrameWindow::InvokeMaximized() const noexcept { - if (m_impl->_maximizedCallback) - m_impl->_maximizedCallback(); -} - -void InfiniFrameWindow::InvokeRestored() const noexcept { - if (m_impl->_restoredCallback) - m_impl->_restoredCallback(); -} - -void InfiniFrameWindow::InvokeMinimized() const noexcept { - if (m_impl->_minimizedCallback) - m_impl->_minimizedCallback(); -} - // --------------------------------------------------------------------------------------------------------------------- // Private methods // --------------------------------------------------------------------------------------------------------------------- diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowEvents.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowEvents.Gtk.cpp new file mode 100644 index 000000000..4770bf254 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowEvents.Gtk.cpp @@ -0,0 +1,113 @@ +#ifdef __linux__ + +#include "Window.Gtk.Internal.h" + +InfiniFrameDialog* InfiniFrameWindow::GetDialog() const { + return m_impl->_dialog.get(); +} + +void InfiniFrameWindow::AddCustomSchemeName(const AutoStringConst scheme) { + if (scheme) + m_impl->_customSchemeNames.emplace_back(scheme); +} + +void InfiniFrameWindow::GetAllMonitors(const GetAllMonitorsCallback callback) const { + if (callback) { + GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(m_impl->_window)); + GdkDisplay* display = gdk_screen_get_display(screen); + int n = gdk_display_get_n_monitors(display); + for (int i = 0; i < n; i++) { + GdkMonitor* monitor = gdk_display_get_monitor(display, i); + Monitor props = {}; + gdk_monitor_get_geometry(monitor, reinterpret_cast(&props.monitor)); + gdk_monitor_get_workarea(monitor, reinterpret_cast(&props.work)); + props.scale = gdk_monitor_get_scale_factor(monitor); + if (!callback(&props)) + break; + } + } +} + +void InfiniFrameWindow::SetClosingCallback(const ClosingCallback callback) { + m_impl->_closingCallback = callback; +} + +void InfiniFrameWindow::SetClosedCallback(const ClosedCallback callback) { + m_impl->_closedCallback = callback; +} + +void InfiniFrameWindow::SetFocusInCallback(const FocusInCallback callback) { + m_impl->_focusInCallback = callback; +} + +void InfiniFrameWindow::SetFocusOutCallback(const FocusOutCallback callback) { + m_impl->_focusOutCallback = callback; +} + +void InfiniFrameWindow::SetMovedCallback(const MovedCallback callback) { + m_impl->_movedCallback = callback; +} + +void InfiniFrameWindow::SetResizedCallback(const ResizedCallback callback) { + m_impl->_resizedCallback = callback; +} + +void InfiniFrameWindow::SetMaximizedCallback(const MaximizedCallback callback) { + m_impl->_maximizedCallback = callback; +} + +void InfiniFrameWindow::SetRestoredCallback(const RestoredCallback callback) { + m_impl->_restoredCallback = callback; +} + +void InfiniFrameWindow::SetMinimizedCallback(const MinimizedCallback callback) { + m_impl->_minimizedCallback = callback; +} + +[[nodiscard]] bool InfiniFrameWindow::InvokeClose() const noexcept { + if (m_impl->_closingCallback) + return m_impl->_closingCallback(); + return false; +} + +void InfiniFrameWindow::InvokeClosed() const noexcept { + if (m_impl->_closedCallback) + m_impl->_closedCallback(); +} + +void InfiniFrameWindow::InvokeFocusIn() const noexcept { + if (m_impl->_focusInCallback) + m_impl->_focusInCallback(); +} + +void InfiniFrameWindow::InvokeFocusOut() const noexcept { + if (m_impl->_focusOutCallback) + m_impl->_focusOutCallback(); +} + +void InfiniFrameWindow::InvokeMove(int x, int y) const noexcept { + if (m_impl->_movedCallback) + m_impl->_movedCallback(x, y); +} + +void InfiniFrameWindow::InvokeResize(int width, int height) const noexcept { + if (m_impl->_resizedCallback) + m_impl->_resizedCallback(width, height); +} + +void InfiniFrameWindow::InvokeMaximized() const noexcept { + if (m_impl->_maximizedCallback) + m_impl->_maximizedCallback(); +} + +void InfiniFrameWindow::InvokeRestored() const noexcept { + if (m_impl->_restoredCallback) + m_impl->_restoredCallback(); +} + +void InfiniFrameWindow::InvokeMinimized() const noexcept { + if (m_impl->_minimizedCallback) + m_impl->_minimizedCallback(); +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowLifecycle.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowLifecycle.Gtk.cpp new file mode 100644 index 000000000..8b6d7d047 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowLifecycle.Gtk.cpp @@ -0,0 +1,79 @@ +#ifdef __linux__ + +#include "Window.Gtk.Internal.h" + +#include + +void InfiniFrameWindow::Center() { + gint windowWidth, windowHeight; + gtk_window_get_size(GTK_WINDOW(m_impl->_window), &windowWidth, &windowHeight); + + GdkRectangle screen = {0}; + + GdkDisplay* d = gdk_display_get_default(); + if (d == nullptr) { + GtkWidget* dialog = gtk_message_dialog_new( + nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "gdk_display_get_default() returned NULL" + ); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return; + } + + GdkMonitor* m = gdk_display_get_primary_monitor(d); + if (m == nullptr) { + m = gdk_display_get_monitor(d, 0); + if (m == nullptr) { + GtkWidget* dialog = gtk_message_dialog_new( + nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "gdk_display_get_primary_monitor() returned NULL" + ); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return; + } + } + + gdk_monitor_get_geometry(m, &screen); + + gtk_window_move( + GTK_WINDOW(m_impl->_window), + (screen.width - windowWidth) / 2, + (screen.height - windowHeight) / 2 + ); +} + +void InfiniFrameWindow::ClearBrowserAutoFill() { + // TODO +} + +void InfiniFrameWindow::Close() { + gtk_window_close(GTK_WINDOW(m_impl->_window)); +} + +void InfiniFrameWindow::ShowNotification(const AutoString title, const AutoString message) { + NotifyNotification* notification = notify_notification_new(title, message, nullptr); + notify_notification_set_icon_from_pixbuf(notification, gtk_window_get_icon(GTK_WINDOW(m_impl->_window))); + notify_notification_show(notification, nullptr); + g_object_unref(G_OBJECT(notification)); +} + +void InfiniFrameWindow::WaitForExit() { + g_signal_connect( + G_OBJECT(m_impl->_window), "destroy", + G_CALLBACK( + +[](GtkWidget*, gpointer) { + gtk_main_quit(); + } + ), + nullptr + ); + gtk_main(); +} + +void InfiniFrameWindow::CloseWebView() { + // Not implemented on Linux +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowState.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowState.Gtk.cpp new file mode 100644 index 000000000..7cc329ac7 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowState.Gtk.cpp @@ -0,0 +1,336 @@ +#ifdef __linux__ + +#include "Window.Gtk.Internal.h" + +#include +#include + +#include "Utils/Common.h" + +void InfiniFrameWindow::GetTransparentEnabled(bool* enabled) const { + *enabled = m_impl->_transparentEnabled; +} + +void InfiniFrameWindow::GetContextMenuEnabled(bool* enabled) const { + *enabled = m_impl->_contextMenuEnabled; +} + +void InfiniFrameWindow::GetZoomEnabled(bool* enabled) const { + *enabled = m_impl->_zoomEnabled; +} + +void InfiniFrameWindow::GetDevToolsEnabled(bool* enabled) const { + WebKitSettings* settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(m_impl->_webview)); + *enabled = webkit_settings_get_enable_developer_extras(settings); +} + +void InfiniFrameWindow::GetFullScreen(bool* fullScreen) const { + *fullScreen = m_impl->_isFullScreen; +} + +void InfiniFrameWindow::GetGrantBrowserPermissions(bool* grant) const { + *grant = m_impl->_grantBrowserPermissions; +} + +AutoString InfiniFrameWindow::GetUserAgent() const { + return AllocateStringCopy(m_impl->_userAgent); +} + +void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const { + *enabled = m_impl->_mediaAutoplayEnabled; +} + +void InfiniFrameWindow::GetFileSystemAccessEnabled(bool* enabled) const { + *enabled = m_impl->_fileSystemAccessEnabled; +} + +void InfiniFrameWindow::GetWebSecurityEnabled(bool* enabled) const { + *enabled = m_impl->_webSecurityEnabled; +} + +void InfiniFrameWindow::GetJavascriptClipboardAccessEnabled(bool* enabled) const { + *enabled = m_impl->_javascriptClipboardAccessEnabled; +} + +void InfiniFrameWindow::GetMediaStreamEnabled(bool* enabled) const { + *enabled = m_impl->_mediaStreamEnabled; +} + +void InfiniFrameWindow::GetSmoothScrollingEnabled(bool* enabled) const { + *enabled = m_impl->_smoothScrollingEnabled; +} + +void InfiniFrameWindow::GetIgnoreCertificateErrorsEnabled(bool* enabled) const { + *enabled = m_impl->_ignoreCertificateErrorsEnabled; +} + +void InfiniFrameWindow::GetMaximized(bool* isMaximized) const { + GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(m_impl->_window)); + GdkWindowState flags = gdk_window_get_state(gdk_window); + *isMaximized = flags & GDK_WINDOW_STATE_MAXIMIZED; +} + +void InfiniFrameWindow::GetMinimized(bool* isMinimized) const { + GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(m_impl->_window)); + GdkWindowState flags = gdk_window_get_state(gdk_window); + *isMinimized = flags & GDK_WINDOW_STATE_ICONIFIED; +} + +void InfiniFrameWindow::GetPosition(int* x, int* y) const { + gtk_window_get_position(GTK_WINDOW(m_impl->_window), x, y); +} + +void InfiniFrameWindow::GetResizable(bool* resizable) const { + *resizable = gtk_window_get_resizable(GTK_WINDOW(m_impl->_window)); +} + +unsigned int InfiniFrameWindow::GetScreenDpi() const { + GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(m_impl->_window)); + gdouble dpi = gdk_screen_get_resolution(screen); + if (dpi < 0) + return 96; + else + return static_cast(dpi); +} + +void InfiniFrameWindow::GetSize(int* width, int* height) const { + gtk_window_get_size(GTK_WINDOW(m_impl->_window), width, height); +} + +void InfiniFrameWindow::GetMaxSize(int* width, int* height) const { + if (width) + *width = m_impl->_maxWidth; + if (height) + *height = m_impl->_maxHeight; +} + +void InfiniFrameWindow::GetMinSize(int* width, int* height) const { + if (width) + *width = m_impl->_minWidth; + if (height) + *height = m_impl->_minHeight; +} + +AutoString InfiniFrameWindow::GetTitle() const { + const char* title = gtk_window_get_title(GTK_WINDOW(m_impl->_window)); + return g_strdup(title ? title : ""); +} + +void InfiniFrameWindow::GetTopmost(bool* topmost) const { + GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(m_impl->_window)); + GdkWindowState flags = gdk_window_get_state(gdk_window); + *topmost = flags & GDK_WINDOW_STATE_ABOVE; +} + +void InfiniFrameWindow::GetZoom(int* zoom) const { + double rawValue = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(m_impl->_webview)); + rawValue = (rawValue * 100.0) + 0.5; + *zoom = static_cast(rawValue); +} + +void InfiniFrameWindow::GetFocused(bool* isFocused) const { + *isFocused = gtk_window_is_active(GTK_WINDOW(m_impl->_window)); +} + +AutoString InfiniFrameWindow::GetIconFileName() const { + return AllocateStringCopy(m_impl->_iconFileName); +} + +void InfiniFrameWindow::NavigateToString(const AutoString content) { + webkit_web_view_load_html(WEBKIT_WEB_VIEW(m_impl->_webview), content, nullptr); +} + +void InfiniFrameWindow::NavigateToUrl(const AutoString url) { + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(m_impl->_webview), url); +} + +void InfiniFrameWindow::Restore() { + gtk_window_present(GTK_WINDOW(m_impl->_window)); +} + +static std::string escapeJsonString(std::string_view input) { + std::string result; + result.reserve(input.size() + 2); + + for (char c : input) { + switch (c) { + case '"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + default: + if (static_cast(c) < 0x20) { + std::format_to(std::back_inserter(result), "\\u{:04x}", static_cast(c)); + } else { + result += c; + } + } + } + + return result; +} + +static void webview_eval_finished(GObject* object, GAsyncResult* result, gpointer) { + GError* error = nullptr; + webkit_web_view_evaluate_javascript_finish(WEBKIT_WEB_VIEW(object), result, &error); + if (error) { + g_warning("JavaScript evaluation failed: %s", error->message); + g_error_free(error); + } +} + +void InfiniFrameWindow::SendWebMessage(const AutoString message) { + std::string escaped = escapeJsonString(message ? message : ""); + + std::string js; + js.append("__dispatchMessageCallback(\""); + js.append(escaped); + js.append("\")"); + + webkit_web_view_evaluate_javascript( + WEBKIT_WEB_VIEW(m_impl->_webview), + js.c_str(), + -1, + nullptr, + nullptr, + nullptr, + webview_eval_finished, + nullptr + ); +} + +void InfiniFrameWindow::SetContextMenuEnabled(const bool enabled) { + m_impl->_contextMenuEnabled = enabled; +} + +void InfiniFrameWindow::SetZoomEnabled(bool enabled) { + (void)enabled; +} + +void InfiniFrameWindow::SetDevToolsEnabled(const bool enabled) { + m_impl->_devToolsEnabled = enabled; + WebKitSettings* settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(m_impl->_webview)); + webkit_settings_set_enable_developer_extras(settings, m_impl->_devToolsEnabled); +} + +void InfiniFrameWindow::SetFullScreen(const bool fullScreen) { + if (fullScreen) + gtk_window_fullscreen(GTK_WINDOW(m_impl->_window)); + else + gtk_window_unfullscreen(GTK_WINDOW(m_impl->_window)); + + m_impl->_isFullScreen = fullScreen; +} + +void InfiniFrameWindow::SetIconFile(const AutoString filename) { + gtk_window_set_icon_from_file(GTK_WINDOW(m_impl->_window), filename, nullptr); + m_impl->_iconFileName = filename ? filename : ""; +} + +void InfiniFrameWindow::SetMinimized(const bool minimized) { + if (minimized) + gtk_window_iconify(GTK_WINDOW(m_impl->_window)); + else + gtk_window_deiconify(GTK_WINDOW(m_impl->_window)); +} + +void InfiniFrameWindow::SetMaximized(const bool maximized) { + if (maximized) + gtk_window_maximize(GTK_WINDOW(m_impl->_window)); + else + gtk_window_unmaximize(GTK_WINDOW(m_impl->_window)); +} + +void InfiniFrameWindow::SetPosition(const int x, const int y) { + gtk_window_move(GTK_WINDOW(m_impl->_window), x, y); +} + +void InfiniFrameWindow::SetResizable(const bool resizable) { + gtk_window_set_resizable(GTK_WINDOW(m_impl->_window), resizable); +} + +void InfiniFrameWindow::SetMinSize(const int width, const int height) { + m_impl->_minWidth = width; + m_impl->_minHeight = height; + m_impl->_hints.min_width = width; + m_impl->_hints.min_height = height; + + gtk_window_set_geometry_hints( + GTK_WINDOW(m_impl->_window), + nullptr, + &m_impl->_hints, + static_cast(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE) + ); +} + +void InfiniFrameWindow::SetMaxSize(const int width, const int height) { + m_impl->_maxWidth = width; + m_impl->_maxHeight = height; + m_impl->_hints.max_width = width; + m_impl->_hints.max_height = height; + + gtk_window_set_geometry_hints( + GTK_WINDOW(m_impl->_window), + nullptr, + &m_impl->_hints, + static_cast(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE) + ); +} + +void InfiniFrameWindow::SetSize(const int width, const int height) { + gtk_window_resize(GTK_WINDOW(m_impl->_window), width, height); +} + +void InfiniFrameWindow::SetTitle(const AutoString title) { + gtk_window_set_title(GTK_WINDOW(m_impl->_window), title); +} + +void InfiniFrameWindow::SetTopmost(const bool topmost) { + gtk_window_set_keep_above(GTK_WINDOW(m_impl->_window), topmost); +} + +void InfiniFrameWindow::SetZoom(const int zoom) { + double newZoom = zoom / 100.0; + webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(m_impl->_webview), newZoom); +} + +void InfiniFrameWindow::SetFocused() { + gtk_window_present(GTK_WINDOW(m_impl->_window)); +} + +void InfiniFrameWindow::SetTransparentEnabled(const bool enabled) { + m_impl->_transparentEnabled = enabled; + + gtk_window_set_decorated(GTK_WINDOW(m_impl->_window), !enabled); + + GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(m_impl->_window)); + GdkVisual* rgba_visual = gdk_screen_get_rgba_visual(screen); + if (rgba_visual) { + gtk_widget_set_visual(GTK_WIDGET(m_impl->_window), rgba_visual); + gtk_widget_set_app_paintable(GTK_WIDGET(m_impl->_window), true); + + GdkRGBA color; + webkit_web_view_get_background_color(WEBKIT_WEB_VIEW(m_impl->_webview), &color); + color.alpha = enabled ? 0 : 1; + webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(m_impl->_webview), &color); + } +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h new file mode 100644 index 000000000..0a78c38fa --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h @@ -0,0 +1,38 @@ +#pragma once + +#ifndef INFINIFRAME_PLATFORM_MAC_WINDOW_COCOA_INTERNAL_H +#define INFINIFRAME_PLATFORM_MAC_WINDOW_COCOA_INTERNAL_H + +#include + +#include +#include +#include + +#include "Core/InfiniFrameWindow.h" +#include "Core/InfiniFrameWindowImpl.h" + +struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { + NSWindow* _window = nil; + WKWebView* _webview = nil; + WKWebViewConfiguration* _webviewConfiguration = nil; + NSWindow* _nativeParentWindow = nil; + id _parentWillCloseObserver = nil; + + std::string _temporaryFilesPath; + + bool _chromeless = false; + + CGFloat _preMaximizedWidth = 0; + CGFloat _preMaximizedHeight = 0; + CGFloat _preMaximizedXPosition = 0; + CGFloat _preMaximizedYPosition = 0; + + std::vector GetMonitors() const; + void SetUserAgent(AutoString userAgent); + void SetPreference(NSString* key, NSNumber* value); + void SetPreference(NSString* key, NSString* value); + void AddCustomScheme(const AutoStringConst scheme, WebResourceRequestedCallback requestHandler); +}; + +#endif // INFINIFRAME_PLATFORM_MAC_WINDOW_COCOA_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm index d55bb721d..92c80013a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm @@ -1,9 +1,9 @@ #ifdef __APPLE__ #include "Core/InfiniFrameWindow.h" #include "Core/InfiniFrameDialog.h" -#include "Core/InfiniFrameWindowImpl.h" #include "Embedded/Embedded.h" #include "Utils/Common.h" +#include "Window.Cocoa.Internal.h" #include "AppDelegate.h" #include "UiDelegate.h" #include "WindowDelegate.h" @@ -15,36 +15,6 @@ using namespace std; -static const int MAX_WINDOW_DIMENSION = 10000; - -// --------------------------------------------------------------------------------------------------------------------- -// Platform Impl -// --------------------------------------------------------------------------------------------------------------------- - -struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl -{ - NSWindow* _window = nil; - WKWebView* _webview = nil; - WKWebViewConfiguration* _webviewConfiguration = nil; - NSWindow* _nativeParentWindow = nil; - id _parentWillCloseObserver = nil; - - std::string _temporaryFilesPath; - - bool _chromeless = false; - - CGFloat _preMaximizedWidth = 0; - CGFloat _preMaximizedHeight = 0; - CGFloat _preMaximizedXPosition = 0; - CGFloat _preMaximizedYPosition = 0; - - std::vector GetMonitors() const; - void SetUserAgent(AutoString userAgent); - void SetPreference(NSString* key, NSNumber* value); - void SetPreference(NSString* key, NSString* value); - void AddCustomScheme(const AutoStringConst scheme, WebResourceRequestedCallback requestHandler); -}; - // --------------------------------------------------------------------------------------------------------------------- // Impl method definitions // --------------------------------------------------------------------------------------------------------------------- @@ -417,618 +387,6 @@ // Window Operations // --------------------------------------------------------------------------------------------------------------------- -void InfiniFrameWindow::Center() -{ - [m_impl->_window center]; - [m_impl->_window makeKeyAndOrderFront: m_impl->_window]; -} - -void InfiniFrameWindow::ClearBrowserAutoFill() -{ - // TODO -} - -void InfiniFrameWindow::Close() -{ - if (m_impl->_parentWillCloseObserver != nil) { - [[NSNotificationCenter defaultCenter] removeObserver:m_impl->_parentWillCloseObserver]; - m_impl->_parentWillCloseObserver = nil; - } - - if (m_impl->_nativeParentWindow != nil && m_impl->_window != nil) { - [m_impl->_nativeParentWindow removeChildWindow:m_impl->_window]; - m_impl->_nativeParentWindow = nil; - } - - if (m_impl->_chromeless) - [m_impl->_window close]; - else - [m_impl->_window performClose: m_impl->_window]; -} - -// --------------------------------------------------------------------------------------------------------------------- -// Get Properties -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::GetTransparentEnabled(bool* enabled) const -{ - *enabled = false; -} - -void InfiniFrameWindow::GetContextMenuEnabled(bool* enabled) const -{ - *enabled = m_impl->_contextMenuEnabled; -} - -void InfiniFrameWindow::GetZoomEnabled(bool* enabled) const -{ - *enabled = m_impl->_zoomEnabled; -} - -void InfiniFrameWindow::GetDevToolsEnabled(bool* enabled) const -{ - *enabled = m_impl->_devToolsEnabled; -} - -void InfiniFrameWindow::GetGrantBrowserPermissions(bool* enabled) const -{ - *enabled = m_impl->_grantBrowserPermissions; -} - -AutoString InfiniFrameWindow::GetUserAgent() const -{ - return AllocateStringCopy(m_impl->_userAgent); -} - -void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const -{ - *enabled = true; -} - -void InfiniFrameWindow::GetFileSystemAccessEnabled(bool* enabled) const -{ - *enabled = m_impl->_fileSystemAccessEnabled; -} - -void InfiniFrameWindow::GetSmoothScrollingEnabled(bool* enabled) const -{ - *enabled = false; -} - -void InfiniFrameWindow::GetWebSecurityEnabled(bool* enabled) const -{ - *enabled = m_impl->_webSecurityEnabled; -} - -void InfiniFrameWindow::GetJavascriptClipboardAccessEnabled(bool* enabled) const -{ - *enabled = m_impl->_javascriptClipboardAccessEnabled; -} - -void InfiniFrameWindow::GetMediaStreamEnabled(bool* enabled) const -{ - *enabled = m_impl->_mediaStreamEnabled; -} - -void InfiniFrameWindow::GetFullScreen(bool* fullScreen) const -{ - *fullScreen = ([m_impl->_window styleMask] & NSWindowStyleMaskFullScreen) != 0; -} - -void InfiniFrameWindow::GetMaximized(bool* isMaximized) const -{ - bool isFullScreen = false; - GetFullScreen(&isFullScreen); - if (isFullScreen) - { - *isMaximized = false; - return; - } - *isMaximized = [m_impl->_window isZoomed]; -} - -void InfiniFrameWindow::GetMinimized(bool* isMinimized) const -{ - *isMinimized = [m_impl->_window isMiniaturized]; -} - -void InfiniFrameWindow::GetPosition(int* x, int* y) const -{ - NSRect frame = [m_impl->_window frame]; - NSScreen* screen = [m_impl->_window screen]; - if (!screen) screen = [NSScreen mainScreen]; - NSRect screenFrame = [screen frame]; - int height = static_cast(roundf(frame.size.height)); - *x = static_cast(roundf(frame.origin.x)); - *y = static_cast(roundf(screenFrame.origin.y + screenFrame.size.height - (frame.origin.y + height))); -} - -void InfiniFrameWindow::GetResizable(bool* resizable) const -{ - *resizable = (([m_impl->_window styleMask] & NSWindowStyleMaskResizable) == NSWindowStyleMaskResizable); -} - -void InfiniFrameWindow::GetIgnoreCertificateErrorsEnabled(bool* enabled) const -{ - *enabled = m_impl->_ignoreCertificateErrorsEnabled; -} - -void InfiniFrameWindow::GetFocused(bool* isFocused) const -{ - if (!isFocused) - return; - - if (!m_impl->_window) - { - *isFocused = false; - return; - } - - *isFocused = [NSApp isActive] && [m_impl->_window isKeyWindow]; -} - -unsigned int InfiniFrameWindow::GetScreenDpi() const -{ - return 72; -} - -void InfiniFrameWindow::GetSize(int* width, int* height) const -{ - NSSize size = [m_impl->_window frame].size; - if (width) *width = static_cast(roundf(size.width)); - if (height) *height = static_cast(roundf(size.height)); -} - -void InfiniFrameWindow::GetMaxSize(int* width, int* height) const -{ - NSSize maxSize = [m_impl->_window maxSize]; - if (width) *width = static_cast(roundf(maxSize.width)); - if (height) *height = static_cast(roundf(maxSize.height)); -} - -void InfiniFrameWindow::GetMinSize(int* width, int* height) const -{ - NSSize minSize = [m_impl->_window minSize]; - if (width) *width = static_cast(roundf(minSize.width)); - if (height) *height = static_cast(roundf(minSize.height)); -} - -AutoString InfiniFrameWindow::GetTitle() const -{ - return AllocateStringCopy(m_impl->_windowTitle); -} - -void InfiniFrameWindow::GetTopmost(bool* topmost) const -{ - *topmost = ([m_impl->_window level] & NSFloatingWindowLevel) == NSFloatingWindowLevel; -} - -void InfiniFrameWindow::GetZoom(int* zoom) const -{ - CGFloat rawValue = [m_impl->_webview magnification]; - rawValue = (rawValue * 100.0) + 0.5; - *zoom = static_cast(rawValue); -} - -AutoString InfiniFrameWindow::GetIconFileName() const -{ - return AllocateStringCopy(m_impl->_iconFileName); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Navigation -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::NavigateToString(AutoString content) -{ - [m_impl->_webview loadHTMLString: [NSString stringWithUTF8String: content] baseURL: nil]; -} - -void InfiniFrameWindow::NavigateToUrl(AutoString url) -{ - NSString* nsurlstring = [NSString stringWithUTF8String: url]; - NSURL *nsurl = [NSURL URLWithString: nsurlstring]; - NSURLRequest *nsrequest = [NSURLRequest requestWithURL: nsurl]; - [m_impl->_webview loadRequest: nsrequest]; -} - -void InfiniFrameWindow::Restore() -{ - bool minimized; - bool maximized; - GetMinimized(&minimized); - GetMaximized(&maximized); - if (minimized) SetMinimized(false); - if (maximized) SetMaximized(false); -} - -void InfiniFrameWindow::SendWebMessage(AutoString message) -{ - NSString* nsmessage = [NSString stringWithUTF8String: message]; - - NSData* data = [ - NSJSONSerialization - dataWithJSONObject: @[nsmessage] - options: 0 - error: nil]; - - NSString *nsmessageJson = [[ - [NSString alloc] - initWithData: data - encoding: NSUTF8StringEncoding] autorelease]; - - nsmessageJson = [ - [nsmessageJson substringToIndex: ([nsmessageJson length] - 1)] - substringFromIndex: 1 - ]; - - NSString *javaScriptToEval = [NSString stringWithFormat: @"__dispatchMessageCallback(%@)", nsmessageJson]; - [m_impl->_webview evaluateJavaScript: javaScriptToEval completionHandler: nil]; -} - -// --------------------------------------------------------------------------------------------------------------------- -// Set Properties -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::SetDevToolsEnabled(bool enabled) -{ - m_impl->_devToolsEnabled = enabled; - m_impl->SetPreference(@"developerExtrasEnabled", enabled ? @YES : @NO); -} - -void InfiniFrameWindow::SetTransparentEnabled(bool enabled) -{ - // Not implemented on macOS -} - -void InfiniFrameWindow::SetContextMenuEnabled(bool enabled) -{ - // Not supported on macOS -} - -void InfiniFrameWindow::SetZoomEnabled(bool enabled) -{ - // Not implemented on macOS -} - -void InfiniFrameWindow::SetIconFile(AutoString filename) -{ - NSString* path = [NSString stringWithUTF8String: filename]; - NSImage* icon = [[NSImage alloc] initWithContentsOfFile: path]; - if (icon != nil) - [[m_impl->_window standardWindowButton: NSWindowDocumentIconButton] setImage: icon]; - - m_impl->_iconFileName = filename ? filename : ""; -} - -void InfiniFrameWindow::SetFullScreen(bool fullScreen) -{ - bool isFullScreen = ([m_impl->_window styleMask] & NSWindowStyleMaskFullScreen) != 0; - if (fullScreen != isFullScreen) - [m_impl->_window toggleFullScreen: nil]; -} - -void InfiniFrameWindow::SetMinimized(bool minimized) -{ - if (m_impl->_window.isMiniaturized == minimized) return; - - if (minimized) - [m_impl->_window miniaturize: nullptr]; - else - [m_impl->_window deminiaturize: nullptr]; -} - -void InfiniFrameWindow::SetMaximized(bool maximized) -{ - if (maximized) - { - NSRect window = [m_impl->_window frame]; - m_impl->_preMaximizedWidth = window.size.width; - m_impl->_preMaximizedHeight = window.size.height; - m_impl->_preMaximizedXPosition = window.origin.x; - m_impl->_preMaximizedYPosition = window.origin.y; - - NSRect screen = [[m_impl->_window screen] visibleFrame]; - [m_impl->_window setFrame: NSMakeRect(screen.origin.x, screen.origin.y, - screen.size.width, screen.size.height) - display: YES]; - } - else if (!maximized && m_impl->_preMaximizedWidth > 0 && m_impl->_preMaximizedHeight > 0) - { - [m_impl->_window setFrame: NSMakeRect(m_impl->_preMaximizedXPosition, - m_impl->_preMaximizedYPosition, - m_impl->_preMaximizedWidth, - m_impl->_preMaximizedHeight) - display: YES]; - } -} - -void InfiniFrameWindow::SetPosition(int x, int y) -{ - NSScreen* screen = [m_impl->_window screen]; - if (!screen) screen = [NSScreen mainScreen]; - NSRect screenFrame = [screen frame]; - - NSRect frame = [m_impl->_window frame]; - int height = static_cast(roundf(frame.size.height)); - - auto left = static_cast(x); - auto top = static_cast(screenFrame.origin.y + screenFrame.size.height - (y + height)); - - [m_impl->_window setFrameOrigin: CGPointMake(left, top)]; -} - -void InfiniFrameWindow::SetResizable(bool resizable) -{ - if (resizable) - m_impl->_window.styleMask |= NSWindowStyleMaskResizable; - else - m_impl->_window.styleMask &= ~NSWindowStyleMaskResizable; -} - -void InfiniFrameWindow::SetSize(int width, int height) -{ - width = width > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : width; - height = height > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : height; - - if (width > m_impl->_window.maxSize.width) width = m_impl->_window.maxSize.width; - if (height > m_impl->_window.maxSize.height) height = m_impl->_window.maxSize.height; - if (width < m_impl->_window.minSize.width) width = m_impl->_window.minSize.width; - if (height < m_impl->_window.minSize.height) height = m_impl->_window.minSize.height; - - NSRect frame = [m_impl->_window frame]; - CGFloat oldHeight = frame.size.height; - frame.size = CGSizeMake(static_cast(width), static_cast(height)); - frame.origin.y -= static_cast(height) - oldHeight; - - [m_impl->_window setFrame: frame display: true]; -} - -void InfiniFrameWindow::SetMinSize(int width, int height) -{ - width = width > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : width; - height = height > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : height; - - [m_impl->_window setMinSize: NSMakeSize(width, height)]; -} - -void InfiniFrameWindow::SetMaxSize(int width, int height) -{ - width = width > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : width; - height = height > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : height; - - [m_impl->_window setMaxSize: NSMakeSize(width, height)]; -} - -void InfiniFrameWindow::SetTitle(AutoString title) -{ - m_impl->_windowTitle = title ? title : ""; - [m_impl->_window setTitle: [NSString stringWithUTF8String: title]]; -} - -void InfiniFrameWindow::SetTopmost(bool topmost) -{ - if (topmost) [m_impl->_window setLevel: NSFloatingWindowLevel]; - else [m_impl->_window setLevel: NSNormalWindowLevel]; -} - -void InfiniFrameWindow::SetZoom(int zoom) -{ - CGFloat newZoom = zoom / 100.0; - [m_impl->_webview setMagnification: newZoom]; -} - -void InfiniFrameWindow::SetFocused() -{ - if (!m_impl->_window) return; - - [NSApp activateIgnoringOtherApps: YES]; - [m_impl->_window makeKeyAndOrderFront: m_impl->_window]; - - if (![m_impl->_window isKeyWindow]) - { - [m_impl->_window orderFrontRegardless]; - [m_impl->_window makeKeyWindow]; - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Notifications / Event loop -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::ShowNotification(AutoString title, AutoString body) -{ - UNMutableNotificationContent *objNotificationContent = [[UNMutableNotificationContent alloc] init]; - objNotificationContent.title = [NSString stringWithUTF8String: title]; - objNotificationContent.body = [NSString stringWithUTF8String: body]; - objNotificationContent.sound = [UNNotificationSound defaultSound]; - UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval: 0.3 repeats: NO]; - UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier: @"three" - content: objNotificationContent - trigger: trigger]; - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - [center addNotificationRequest: request withCompletionHandler: ^(NSError * _Nullable error) {}]; -} - -void InfiniFrameWindow::WaitForExit() -{ - if (![NSApp isRunning]) { - [NSApp run]; - return; - } - - __block bool windowClosed = false; - id observer = [[NSNotificationCenter defaultCenter] - addObserverForName: NSWindowWillCloseNotification - object: m_impl->_window - queue: nil - usingBlock: ^(NSNotification*) { - windowClosed = true; - }]; - - while (!windowClosed) { - [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode - beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.05]]; - } - - [[NSNotificationCenter defaultCenter] removeObserver: observer]; -} - -void InfiniFrameWindow::CloseWebView() -{ - // Not implemented on macOS -} - -// --------------------------------------------------------------------------------------------------------------------- -// Callbacks -// --------------------------------------------------------------------------------------------------------------------- - -InfiniFrameDialog* InfiniFrameWindow::GetDialog() const -{ - return m_impl->_dialog.get(); -} - -void InfiniFrameWindow::AddCustomSchemeName(const AutoStringConst scheme) -{ - if (scheme) - m_impl->_customSchemeNames.emplace_back(scheme); -} - -void InfiniFrameWindow::GetAllMonitors(GetAllMonitorsCallback callback) const -{ - if (callback) - { - for (NSScreen* screen in [NSScreen screens]) - { - Monitor props = {}; - - NSRect frame = [screen frame]; - props.monitor.x = static_cast(roundf(frame.origin.x)); - props.monitor.y = static_cast(roundf(frame.origin.y)); - props.monitor.width = static_cast(roundf(frame.size.width)); - props.monitor.height = static_cast(roundf(frame.size.height)); - - NSRect vframe = [screen visibleFrame]; - props.work.x = static_cast(roundf(vframe.origin.x)); - props.work.y = static_cast(roundf(vframe.origin.y)); - props.work.width = static_cast(roundf(vframe.size.width)); - props.work.height = static_cast(roundf(vframe.size.height)); - - props.scale = [screen backingScaleFactor]; - - callback(&props); - } - } -} - -void InfiniFrameWindow::SetClosingCallback(const ClosingCallback callback) -{ - m_impl->_closingCallback = callback; -} - -void InfiniFrameWindow::SetClosedCallback(const ClosedCallback callback) -{ - m_impl->_closedCallback = callback; -} - -void InfiniFrameWindow::SetFocusInCallback(const FocusInCallback callback) -{ - m_impl->_focusInCallback = callback; -} - -void InfiniFrameWindow::SetFocusOutCallback(const FocusOutCallback callback) -{ - m_impl->_focusOutCallback = callback; -} - -void InfiniFrameWindow::SetMovedCallback(const MovedCallback callback) -{ - m_impl->_movedCallback = callback; -} - -void InfiniFrameWindow::SetResizedCallback(const ResizedCallback callback) -{ - m_impl->_resizedCallback = callback; -} - -void InfiniFrameWindow::SetMaximizedCallback(const MaximizedCallback callback) -{ - m_impl->_maximizedCallback = callback; -} - -void InfiniFrameWindow::SetRestoredCallback(const RestoredCallback callback) -{ - m_impl->_restoredCallback = callback; -} - -void InfiniFrameWindow::SetMinimizedCallback(const MinimizedCallback callback) -{ - m_impl->_minimizedCallback = callback; -} - -void InfiniFrameWindow::Invoke(ACTION callback) -{ - if ([NSThread isMainThread]) - callback(); - else - dispatch_sync(dispatch_get_main_queue(), ^(void){ callback(); }); -} - -[[nodiscard]] bool InfiniFrameWindow::InvokeClose() const noexcept -{ - if (m_impl->_closingCallback) - return m_impl->_closingCallback(); - return false; -} - -void InfiniFrameWindow::InvokeClosed() const noexcept -{ - if (m_impl->_closedCallback) - m_impl->_closedCallback(); -} - -void InfiniFrameWindow::InvokeFocusIn() const noexcept -{ - if (m_impl->_focusInCallback) - m_impl->_focusInCallback(); -} - -void InfiniFrameWindow::InvokeFocusOut() const noexcept -{ - if (m_impl->_focusOutCallback) - m_impl->_focusOutCallback(); -} - -void InfiniFrameWindow::InvokeMove(int x, int y) const noexcept -{ - if (m_impl->_movedCallback) - m_impl->_movedCallback(x, y); -} - -void InfiniFrameWindow::InvokeResize(int width, int height) const noexcept -{ - if (m_impl->_resizedCallback) - m_impl->_resizedCallback(width, height); -} - -void InfiniFrameWindow::InvokeMaximized() const noexcept -{ - if (m_impl->_maximizedCallback) - m_impl->_maximizedCallback(); -} - -void InfiniFrameWindow::InvokeRestored() const noexcept -{ - if (m_impl->_restoredCallback) - m_impl->_restoredCallback(); -} - -void InfiniFrameWindow::InvokeMinimized() const noexcept -{ - if (m_impl->_minimizedCallback) - m_impl->_minimizedCallback(); -} - // --------------------------------------------------------------------------------------------------------------------- // Private methods // --------------------------------------------------------------------------------------------------------------------- diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm new file mode 100644 index 000000000..f9b57e617 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm @@ -0,0 +1,151 @@ +#ifdef __APPLE__ + +#include "Window.Cocoa.Internal.h" + +InfiniFrameDialog* InfiniFrameWindow::GetDialog() const +{ + return m_impl->_dialog.get(); +} + +void InfiniFrameWindow::AddCustomSchemeName(const AutoStringConst scheme) +{ + if (scheme) + m_impl->_customSchemeNames.emplace_back(scheme); +} + +void InfiniFrameWindow::GetAllMonitors(GetAllMonitorsCallback callback) const +{ + if (callback) + { + for (NSScreen* screen in [NSScreen screens]) + { + Monitor props = {}; + + NSRect frame = [screen frame]; + props.monitor.x = static_cast(roundf(frame.origin.x)); + props.monitor.y = static_cast(roundf(frame.origin.y)); + props.monitor.width = static_cast(roundf(frame.size.width)); + props.monitor.height = static_cast(roundf(frame.size.height)); + + NSRect vframe = [screen visibleFrame]; + props.work.x = static_cast(roundf(vframe.origin.x)); + props.work.y = static_cast(roundf(vframe.origin.y)); + props.work.width = static_cast(roundf(vframe.size.width)); + props.work.height = static_cast(roundf(vframe.size.height)); + + props.scale = [screen backingScaleFactor]; + + callback(&props); + } + } +} + +void InfiniFrameWindow::SetClosingCallback(const ClosingCallback callback) +{ + m_impl->_closingCallback = callback; +} + +void InfiniFrameWindow::SetClosedCallback(const ClosedCallback callback) +{ + m_impl->_closedCallback = callback; +} + +void InfiniFrameWindow::SetFocusInCallback(const FocusInCallback callback) +{ + m_impl->_focusInCallback = callback; +} + +void InfiniFrameWindow::SetFocusOutCallback(const FocusOutCallback callback) +{ + m_impl->_focusOutCallback = callback; +} + +void InfiniFrameWindow::SetMovedCallback(const MovedCallback callback) +{ + m_impl->_movedCallback = callback; +} + +void InfiniFrameWindow::SetResizedCallback(const ResizedCallback callback) +{ + m_impl->_resizedCallback = callback; +} + +void InfiniFrameWindow::SetMaximizedCallback(const MaximizedCallback callback) +{ + m_impl->_maximizedCallback = callback; +} + +void InfiniFrameWindow::SetRestoredCallback(const RestoredCallback callback) +{ + m_impl->_restoredCallback = callback; +} + +void InfiniFrameWindow::SetMinimizedCallback(const MinimizedCallback callback) +{ + m_impl->_minimizedCallback = callback; +} + +void InfiniFrameWindow::Invoke(ACTION callback) +{ + if ([NSThread isMainThread]) + callback(); + else + dispatch_sync(dispatch_get_main_queue(), ^(void){ callback(); }); +} + +[[nodiscard]] bool InfiniFrameWindow::InvokeClose() const noexcept +{ + if (m_impl->_closingCallback) + return m_impl->_closingCallback(); + return false; +} + +void InfiniFrameWindow::InvokeClosed() const noexcept +{ + if (m_impl->_closedCallback) + m_impl->_closedCallback(); +} + +void InfiniFrameWindow::InvokeFocusIn() const noexcept +{ + if (m_impl->_focusInCallback) + m_impl->_focusInCallback(); +} + +void InfiniFrameWindow::InvokeFocusOut() const noexcept +{ + if (m_impl->_focusOutCallback) + m_impl->_focusOutCallback(); +} + +void InfiniFrameWindow::InvokeMove(int x, int y) const noexcept +{ + if (m_impl->_movedCallback) + m_impl->_movedCallback(x, y); +} + +void InfiniFrameWindow::InvokeResize(int width, int height) const noexcept +{ + if (m_impl->_resizedCallback) + m_impl->_resizedCallback(width, height); +} + +void InfiniFrameWindow::InvokeMaximized() const noexcept +{ + if (m_impl->_maximizedCallback) + m_impl->_maximizedCallback(); +} + +void InfiniFrameWindow::InvokeRestored() const noexcept +{ + if (m_impl->_restoredCallback) + m_impl->_restoredCallback(); +} + +void InfiniFrameWindow::InvokeMinimized() const noexcept +{ + if (m_impl->_minimizedCallback) + m_impl->_minimizedCallback(); +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowLifecycle.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowLifecycle.Cocoa.mm new file mode 100644 index 000000000..d85e661e9 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowLifecycle.Cocoa.mm @@ -0,0 +1,77 @@ +#ifdef __APPLE__ + +#include "Window.Cocoa.Internal.h" + +void InfiniFrameWindow::Center() +{ + [m_impl->_window center]; + [m_impl->_window makeKeyAndOrderFront: m_impl->_window]; +} + +void InfiniFrameWindow::ClearBrowserAutoFill() +{ + // TODO +} + +void InfiniFrameWindow::Close() +{ + if (m_impl->_parentWillCloseObserver != nil) { + [[NSNotificationCenter defaultCenter] removeObserver:m_impl->_parentWillCloseObserver]; + m_impl->_parentWillCloseObserver = nil; + } + + if (m_impl->_nativeParentWindow != nil && m_impl->_window != nil) { + [m_impl->_nativeParentWindow removeChildWindow:m_impl->_window]; + m_impl->_nativeParentWindow = nil; + } + + if (m_impl->_chromeless) + [m_impl->_window close]; + else + [m_impl->_window performClose: m_impl->_window]; +} + +void InfiniFrameWindow::ShowNotification(AutoString title, AutoString body) +{ + UNMutableNotificationContent *objNotificationContent = [[UNMutableNotificationContent alloc] init]; + objNotificationContent.title = [NSString stringWithUTF8String: title]; + objNotificationContent.body = [NSString stringWithUTF8String: body]; + objNotificationContent.sound = [UNNotificationSound defaultSound]; + UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval: 0.3 repeats: NO]; + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier: @"three" + content: objNotificationContent + trigger: trigger]; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center addNotificationRequest: request withCompletionHandler: ^(NSError * _Nullable error) {}]; +} + +void InfiniFrameWindow::WaitForExit() +{ + if (![NSApp isRunning]) { + [NSApp run]; + return; + } + + __block bool windowClosed = false; + id observer = [[NSNotificationCenter defaultCenter] + addObserverForName: NSWindowWillCloseNotification + object: m_impl->_window + queue: nil + usingBlock: ^(NSNotification*) { + windowClosed = true; + }]; + + while (!windowClosed) { + [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode + beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.05]]; + } + + [[NSNotificationCenter defaultCenter] removeObserver: observer]; +} + +void InfiniFrameWindow::CloseWebView() +{ + // Not implemented on macOS +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowState.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowState.Cocoa.mm new file mode 100644 index 000000000..f4e339432 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowState.Cocoa.mm @@ -0,0 +1,383 @@ +#ifdef __APPLE__ + +#include "Window.Cocoa.Internal.h" + +#include "Utils/Common.h" + +static const int MAX_WINDOW_DIMENSION = 10000; + +void InfiniFrameWindow::GetTransparentEnabled(bool* enabled) const +{ + *enabled = false; +} + +void InfiniFrameWindow::GetContextMenuEnabled(bool* enabled) const +{ + *enabled = m_impl->_contextMenuEnabled; +} + +void InfiniFrameWindow::GetZoomEnabled(bool* enabled) const +{ + *enabled = m_impl->_zoomEnabled; +} + +void InfiniFrameWindow::GetDevToolsEnabled(bool* enabled) const +{ + *enabled = m_impl->_devToolsEnabled; +} + +void InfiniFrameWindow::GetGrantBrowserPermissions(bool* enabled) const +{ + *enabled = m_impl->_grantBrowserPermissions; +} + +AutoString InfiniFrameWindow::GetUserAgent() const +{ + return AllocateStringCopy(m_impl->_userAgent); +} + +void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const +{ + *enabled = true; +} + +void InfiniFrameWindow::GetFileSystemAccessEnabled(bool* enabled) const +{ + *enabled = m_impl->_fileSystemAccessEnabled; +} + +void InfiniFrameWindow::GetSmoothScrollingEnabled(bool* enabled) const +{ + *enabled = false; +} + +void InfiniFrameWindow::GetWebSecurityEnabled(bool* enabled) const +{ + *enabled = m_impl->_webSecurityEnabled; +} + +void InfiniFrameWindow::GetJavascriptClipboardAccessEnabled(bool* enabled) const +{ + *enabled = m_impl->_javascriptClipboardAccessEnabled; +} + +void InfiniFrameWindow::GetMediaStreamEnabled(bool* enabled) const +{ + *enabled = m_impl->_mediaStreamEnabled; +} + +void InfiniFrameWindow::GetFullScreen(bool* fullScreen) const +{ + *fullScreen = ([m_impl->_window styleMask] & NSWindowStyleMaskFullScreen) != 0; +} + +void InfiniFrameWindow::GetMaximized(bool* isMaximized) const +{ + bool isFullScreen = false; + GetFullScreen(&isFullScreen); + if (isFullScreen) + { + *isMaximized = false; + return; + } + *isMaximized = [m_impl->_window isZoomed]; +} + +void InfiniFrameWindow::GetMinimized(bool* isMinimized) const +{ + *isMinimized = [m_impl->_window isMiniaturized]; +} + +void InfiniFrameWindow::GetPosition(int* x, int* y) const +{ + NSRect frame = [m_impl->_window frame]; + NSScreen* screen = [m_impl->_window screen]; + if (!screen) screen = [NSScreen mainScreen]; + NSRect screenFrame = [screen frame]; + int height = static_cast(roundf(frame.size.height)); + *x = static_cast(roundf(frame.origin.x)); + *y = static_cast(roundf(screenFrame.origin.y + screenFrame.size.height - (frame.origin.y + height))); +} + +void InfiniFrameWindow::GetResizable(bool* resizable) const +{ + *resizable = (([m_impl->_window styleMask] & NSWindowStyleMaskResizable) == NSWindowStyleMaskResizable); +} + +void InfiniFrameWindow::GetIgnoreCertificateErrorsEnabled(bool* enabled) const +{ + *enabled = m_impl->_ignoreCertificateErrorsEnabled; +} + +void InfiniFrameWindow::GetFocused(bool* isFocused) const +{ + if (!isFocused) + return; + + if (!m_impl->_window) + { + *isFocused = false; + return; + } + + *isFocused = [NSApp isActive] && [m_impl->_window isKeyWindow]; +} + +unsigned int InfiniFrameWindow::GetScreenDpi() const +{ + return 72; +} + +void InfiniFrameWindow::GetSize(int* width, int* height) const +{ + NSSize size = [m_impl->_window frame].size; + if (width) *width = static_cast(roundf(size.width)); + if (height) *height = static_cast(roundf(size.height)); +} + +void InfiniFrameWindow::GetMaxSize(int* width, int* height) const +{ + NSSize maxSize = [m_impl->_window maxSize]; + if (width) *width = static_cast(roundf(maxSize.width)); + if (height) *height = static_cast(roundf(maxSize.height)); +} + +void InfiniFrameWindow::GetMinSize(int* width, int* height) const +{ + NSSize minSize = [m_impl->_window minSize]; + if (width) *width = static_cast(roundf(minSize.width)); + if (height) *height = static_cast(roundf(minSize.height)); +} + +AutoString InfiniFrameWindow::GetTitle() const +{ + return AllocateStringCopy(m_impl->_windowTitle); +} + +void InfiniFrameWindow::GetTopmost(bool* topmost) const +{ + *topmost = ([m_impl->_window level] & NSFloatingWindowLevel) == NSFloatingWindowLevel; +} + +void InfiniFrameWindow::GetZoom(int* zoom) const +{ + CGFloat rawValue = [m_impl->_webview magnification]; + rawValue = (rawValue * 100.0) + 0.5; + *zoom = static_cast(rawValue); +} + +AutoString InfiniFrameWindow::GetIconFileName() const +{ + return AllocateStringCopy(m_impl->_iconFileName); +} + +void InfiniFrameWindow::NavigateToString(AutoString content) +{ + [m_impl->_webview loadHTMLString: [NSString stringWithUTF8String: content] baseURL: nil]; +} + +void InfiniFrameWindow::NavigateToUrl(AutoString url) +{ + NSString* nsurlstring = [NSString stringWithUTF8String: url]; + NSURL *nsurl = [NSURL URLWithString: nsurlstring]; + NSURLRequest *nsrequest = [NSURLRequest requestWithURL: nsurl]; + [m_impl->_webview loadRequest: nsrequest]; +} + +void InfiniFrameWindow::Restore() +{ + bool minimized; + bool maximized; + GetMinimized(&minimized); + GetMaximized(&maximized); + if (minimized) SetMinimized(false); + if (maximized) SetMaximized(false); +} + +void InfiniFrameWindow::SendWebMessage(AutoString message) +{ + NSString* nsmessage = [NSString stringWithUTF8String: message]; + + NSData* data = [ + NSJSONSerialization + dataWithJSONObject: @[nsmessage] + options: 0 + error: nil]; + + NSString *nsmessageJson = [[ + [NSString alloc] + initWithData: data + encoding: NSUTF8StringEncoding] autorelease]; + + nsmessageJson = [ + [nsmessageJson substringToIndex: ([nsmessageJson length] - 1)] + substringFromIndex: 1 + ]; + + NSString *javaScriptToEval = [NSString stringWithFormat: @"__dispatchMessageCallback(%@)", nsmessageJson]; + [m_impl->_webview evaluateJavaScript: javaScriptToEval completionHandler: nil]; +} + +void InfiniFrameWindow::SetDevToolsEnabled(bool enabled) +{ + m_impl->_devToolsEnabled = enabled; + m_impl->SetPreference(@"developerExtrasEnabled", enabled ? @YES : @NO); +} + +void InfiniFrameWindow::SetTransparentEnabled(bool enabled) +{ + (void)enabled; +} + +void InfiniFrameWindow::SetContextMenuEnabled(bool enabled) +{ + (void)enabled; +} + +void InfiniFrameWindow::SetZoomEnabled(bool enabled) +{ + (void)enabled; +} + +void InfiniFrameWindow::SetIconFile(AutoString filename) +{ + NSString* path = [NSString stringWithUTF8String: filename]; + NSImage* icon = [[NSImage alloc] initWithContentsOfFile: path]; + if (icon != nil) + [[m_impl->_window standardWindowButton: NSWindowDocumentIconButton] setImage: icon]; + + m_impl->_iconFileName = filename ? filename : ""; +} + +void InfiniFrameWindow::SetFullScreen(bool fullScreen) +{ + bool isFullScreen = ([m_impl->_window styleMask] & NSWindowStyleMaskFullScreen) != 0; + if (fullScreen != isFullScreen) + [m_impl->_window toggleFullScreen: nil]; +} + +void InfiniFrameWindow::SetMinimized(bool minimized) +{ + if (m_impl->_window.isMiniaturized == minimized) return; + + if (minimized) + [m_impl->_window miniaturize: nullptr]; + else + [m_impl->_window deminiaturize: nullptr]; +} + +void InfiniFrameWindow::SetMaximized(bool maximized) +{ + if (maximized) + { + NSRect window = [m_impl->_window frame]; + m_impl->_preMaximizedWidth = window.size.width; + m_impl->_preMaximizedHeight = window.size.height; + m_impl->_preMaximizedXPosition = window.origin.x; + m_impl->_preMaximizedYPosition = window.origin.y; + + NSRect screen = [[m_impl->_window screen] visibleFrame]; + [m_impl->_window setFrame: NSMakeRect(screen.origin.x, screen.origin.y, + screen.size.width, screen.size.height) + display: YES]; + } + else if (!maximized && m_impl->_preMaximizedWidth > 0 && m_impl->_preMaximizedHeight > 0) + { + [m_impl->_window setFrame: NSMakeRect(m_impl->_preMaximizedXPosition, + m_impl->_preMaximizedYPosition, + m_impl->_preMaximizedWidth, + m_impl->_preMaximizedHeight) + display: YES]; + } +} + +void InfiniFrameWindow::SetPosition(int x, int y) +{ + NSScreen* screen = [m_impl->_window screen]; + if (!screen) screen = [NSScreen mainScreen]; + NSRect screenFrame = [screen frame]; + + NSRect frame = [m_impl->_window frame]; + int height = static_cast(roundf(frame.size.height)); + + auto left = static_cast(x); + auto top = static_cast(screenFrame.origin.y + screenFrame.size.height - (y + height)); + + [m_impl->_window setFrameOrigin: CGPointMake(left, top)]; +} + +void InfiniFrameWindow::SetResizable(bool resizable) +{ + if (resizable) + m_impl->_window.styleMask |= NSWindowStyleMaskResizable; + else + m_impl->_window.styleMask &= ~NSWindowStyleMaskResizable; +} + +void InfiniFrameWindow::SetSize(int width, int height) +{ + width = width > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : width; + height = height > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : height; + + if (width > m_impl->_window.maxSize.width) width = m_impl->_window.maxSize.width; + if (height > m_impl->_window.maxSize.height) height = m_impl->_window.maxSize.height; + if (width < m_impl->_window.minSize.width) width = m_impl->_window.minSize.width; + if (height < m_impl->_window.minSize.height) height = m_impl->_window.minSize.height; + + NSRect frame = [m_impl->_window frame]; + CGFloat oldHeight = frame.size.height; + frame.size = CGSizeMake(static_cast(width), static_cast(height)); + frame.origin.y -= static_cast(height) - oldHeight; + + [m_impl->_window setFrame: frame display: true]; +} + +void InfiniFrameWindow::SetMinSize(int width, int height) +{ + width = width > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : width; + height = height > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : height; + + [m_impl->_window setMinSize: NSMakeSize(width, height)]; +} + +void InfiniFrameWindow::SetMaxSize(int width, int height) +{ + width = width > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : width; + height = height > MAX_WINDOW_DIMENSION ? MAX_WINDOW_DIMENSION : height; + + [m_impl->_window setMaxSize: NSMakeSize(width, height)]; +} + +void InfiniFrameWindow::SetTitle(AutoString title) +{ + m_impl->_windowTitle = title ? title : ""; + [m_impl->_window setTitle: [NSString stringWithUTF8String: title]]; +} + +void InfiniFrameWindow::SetTopmost(bool topmost) +{ + if (topmost) [m_impl->_window setLevel: NSFloatingWindowLevel]; + else [m_impl->_window setLevel: NSNormalWindowLevel]; +} + +void InfiniFrameWindow::SetZoom(int zoom) +{ + CGFloat newZoom = zoom / 100.0; + [m_impl->_webview setMagnification: newZoom]; +} + +void InfiniFrameWindow::SetFocused() +{ + if (!m_impl->_window) return; + + [NSApp activateIgnoringOtherApps: YES]; + [m_impl->_window makeKeyAndOrderFront: m_impl->_window]; + + if (![m_impl->_window isKeyWindow]) + { + [m_impl->_window orderFrontRegardless]; + [m_impl->_window makeKeyWindow]; + } +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h new file mode 100644 index 000000000..684519507 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h @@ -0,0 +1,66 @@ +#pragma once + +#ifndef INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_INTERNAL_H +#define INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_INTERNAL_H + +#include +#include + +#include +#include +#include + +#include "Core/InfiniFrameWindow.h" +#include "Core/InfiniFrameWindowImpl.h" +#include "ToastHandler.h" +#include "Utils/Common.h" + +struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { + std::wstring _temporaryFilesPath; + std::wstring _notificationRegistrationId; + + bool _notificationsEnabled = false; + bool _isInitialized = false; + bool _isWebView2Initializing = false; + std::atomic _isClosingOrClosed = false; + bool _centerOnInitialize = false; + bool _chromeless = false; + bool _fullScreen = false; + bool _maximized = false; + bool _minimized = false; + bool _resizable = true; + bool _topmost = false; + bool _useOsDefaultLocation = false; + bool _useOsDefaultSize = false; + bool _hasSavedRect = false; + + RECT _savedRect = {}; + + int _zoom = 100; + int _minWidth = MinWindowDimension; + int _minHeight = MinWindowDimension; + int _maxWidth = MaxWindowDimension; + int _maxHeight = MaxWindowDimension; + + HWND _hWnd = nullptr; + HWND _pendingOwnerHwnd = nullptr; + bool _ownerAssigned = false; + wil::com_ptr _webviewController; + wil::com_ptr _webviewWindow; + wil::com_ptr _webviewEnvironment; + + EventRegistrationToken _webMessageReceivedToken = {}; + EventRegistrationToken _webResourceRequestedTokenForCustomScheme = {}; + EventRegistrationToken _permissionRequestedToken = {}; + EventRegistrationToken _windowClosedToken = {}; + EventRegistrationToken _windowClosingToken = {}; + EventRegistrationToken _documentTitleChangedToken = {}; + EventRegistrationToken _coreWebView2InitializedToken = {}; + bool _hasWebMessageReceivedToken = false; + bool _hasWebResourceRequestedToken = false; + bool _hasPermissionRequestedToken = false; + + std::unique_ptr _toastHandler; +}; + +#endif // INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp index df8950b63..453360a25 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp @@ -21,11 +21,11 @@ #include "Core/InfiniFrameDialog.h" #include "Core/InfiniFrameWindow.h" -#include "Core/InfiniFrameWindowImpl.h" #include #include "DarkMode.h" #include "ToastHandler.h" #include "Utils/Common.h" +#include "Window.Win32.Internal.h" #include "Embedded/Embedded.h" @@ -37,58 +37,6 @@ using namespace WinToastLib; using namespace Microsoft::WRL; -// --------------------------------------------------------------------------------------------------------------------- -// InfiniFrameWindow::Impl definition -// --------------------------------------------------------------------------------------------------------------------- - -struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { - std::wstring _temporaryFilesPath; - std::wstring _notificationRegistrationId; - - bool _notificationsEnabled = false; - bool _isInitialized = false; - bool _isWebView2Initializing = false; - std::atomic _isClosingOrClosed = false; - bool _centerOnInitialize = false; - bool _chromeless = false; - bool _fullScreen = false; - bool _maximized = false; - bool _minimized = false; - bool _resizable = true; - bool _topmost = false; - bool _useOsDefaultLocation = false; - bool _useOsDefaultSize = false; - bool _hasSavedRect = false; - - RECT _savedRect = {}; - - int _zoom = 100; - int _minWidth = MinWindowDimension; - int _minHeight = MinWindowDimension; - int _maxWidth = MaxWindowDimension; - int _maxHeight = MaxWindowDimension; - - HWND _hWnd = nullptr; - HWND _pendingOwnerHwnd = nullptr; - bool _ownerAssigned = false; - wil::com_ptr _webviewController; - wil::com_ptr _webviewWindow; - wil::com_ptr _webviewEnvironment; - - EventRegistrationToken _webMessageReceivedToken = {}; - EventRegistrationToken _webResourceRequestedTokenForCustomScheme = {}; - EventRegistrationToken _permissionRequestedToken = {}; - EventRegistrationToken _windowClosedToken = {}; - EventRegistrationToken _windowClosingToken = {}; - EventRegistrationToken _documentTitleChangedToken = {}; - EventRegistrationToken _coreWebView2InitializedToken = {}; - bool _hasWebMessageReceivedToken = false; - bool _hasWebResourceRequestedToken = false; - bool _hasPermissionRequestedToken = false; - - std::unique_ptr _toastHandler; -}; - LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); auto CLASS_NAME = L"InfiniFrame"; std::atomic _hInstance{nullptr}; @@ -803,486 +751,6 @@ void InfiniFrameWindow::CloseWebView() { } -void InfiniFrameWindow::Center() { - int screenDpi = GetDpiForWindow(m_impl->_hWnd); - int screenHeight = GetSystemMetricsForDpi(SM_CYSCREEN, screenDpi); - int screenWidth = GetSystemMetricsForDpi(SM_CXSCREEN, screenDpi); - - RECT windowRect = {}; - GetWindowRect(m_impl->_hWnd, &windowRect); - int windowHeight = windowRect.bottom - windowRect.top; - int windowWidth = windowRect.right - windowRect.left; - - int left = (screenWidth / 2) - (windowWidth / 2); - int top = (screenHeight / 2) - (windowHeight / 2); - - SetPosition(left, top); -} - -void InfiniFrameWindow::Close() { - PostMessage(m_impl->_hWnd, WM_CLOSE, 0, 0); -} - -void InfiniFrameWindow::GetTransparentEnabled(bool* enabled) const { - if (!m_impl->_webviewController) { - *enabled = m_impl->_transparentEnabled; - return; - } - wil::com_ptr controller2; - if (FAILED(m_impl->_webviewController->QueryInterface(&controller2)) || !controller2) { - *enabled = m_impl->_transparentEnabled; - return; - } - COREWEBVIEW2_COLOR backgroundColor; - controller2->get_DefaultBackgroundColor(&backgroundColor); - *enabled = backgroundColor.A == 0; -} - -void InfiniFrameWindow::GetContextMenuEnabled(bool* enabled) const { - if (!m_impl->_webviewWindow) { - *enabled = m_impl->_contextMenuEnabled; - return; - } - wil::com_ptr settings; - if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { - BOOL boolValue = FALSE; - settings->get_AreDefaultContextMenusEnabled(&boolValue); - *enabled = (boolValue != FALSE); - } -} - -void InfiniFrameWindow::GetZoomEnabled(bool* enabled) const { - if (!m_impl->_webviewWindow) { - *enabled = m_impl->_zoomEnabled; - return; - } - wil::com_ptr settings; - if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { - BOOL boolValue = FALSE; - settings->get_IsZoomControlEnabled(&boolValue); - *enabled = (boolValue != FALSE); - } -} - -void InfiniFrameWindow::GetDevToolsEnabled(bool* enabled) const { - if (!m_impl->_webviewWindow) { - *enabled = m_impl->_devToolsEnabled; - return; - } - wil::com_ptr settings; - if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { - BOOL boolValue = FALSE; - settings->get_AreDevToolsEnabled(&boolValue); - *enabled = (boolValue != FALSE); - } -} - -void InfiniFrameWindow::GetFullScreen(bool* fullScreen) const { - LONG lStyles = GetWindowLong(m_impl->_hWnd, GWL_STYLE); - *fullScreen = (lStyles & WS_POPUP) != 0; -} - -void InfiniFrameWindow::GetGrantBrowserPermissions(bool* grant) const { - *grant = m_impl->_grantBrowserPermissions; -} - -AutoString InfiniFrameWindow::GetUserAgent() const { - return AllocateStringCopy(m_impl->_userAgent); -} - -void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const { - *enabled = m_impl->_mediaAutoplayEnabled; -} - -void InfiniFrameWindow::GetFileSystemAccessEnabled(bool* enabled) const { - *enabled = m_impl->_fileSystemAccessEnabled; -} - -void InfiniFrameWindow::GetWebSecurityEnabled(bool* enabled) const { - *enabled = m_impl->_webSecurityEnabled; -} - -void InfiniFrameWindow::GetJavascriptClipboardAccessEnabled(bool* enabled) const { - *enabled = m_impl->_javascriptClipboardAccessEnabled; -} - -void InfiniFrameWindow::GetMediaStreamEnabled(bool* enabled) const { - *enabled = m_impl->_mediaStreamEnabled; -} - -void InfiniFrameWindow::GetSmoothScrollingEnabled(bool* enabled) const { - *enabled = m_impl->_smoothScrollingEnabled; -} - -void InfiniFrameWindow::GetIgnoreCertificateErrorsEnabled(bool* enabled) const { - *enabled = m_impl->_ignoreCertificateErrorsEnabled; -} - -void InfiniFrameWindow::GetFocused(bool* isFocused) const { - *isFocused = GetFocus() == m_impl->_hWnd; -} - -void InfiniFrameWindow::GetNotificationsEnabled(bool* enabled) const { - *enabled = m_impl->_notificationsEnabled; -} - -AutoString InfiniFrameWindow::GetIconFileName() const { - return AllocateStringCopy(m_impl->_iconFileName); -} - -void InfiniFrameWindow::GetMaximized(bool* isMaximized) const { - LONG lStyles = GetWindowLong(m_impl->_hWnd, GWL_STYLE); - *isMaximized = (lStyles & WS_MAXIMIZE) != 0; -} - -void InfiniFrameWindow::GetMinimized(bool* isMinimized) const { - LONG lStyles = GetWindowLong(m_impl->_hWnd, GWL_STYLE); - *isMinimized = (lStyles & WS_MINIMIZE) != 0; -} - -void InfiniFrameWindow::GetPosition(int* x, int* y) const { - RECT rect = {}; - GetWindowRect(m_impl->_hWnd, &rect); - if (x) - *x = rect.left; - if (y) - *y = rect.top; -} - -void InfiniFrameWindow::GetResizable(bool* resizable) const { - LONG lStyles = GetWindowLong(m_impl->_hWnd, GWL_STYLE); - *resizable = (lStyles & WS_THICKFRAME) != 0; -} - -unsigned int InfiniFrameWindow::GetScreenDpi() const { - return GetDpiForWindow(m_impl->_hWnd); -} - -void InfiniFrameWindow::GetSize(int* width, int* height) const { - RECT rect = {}; - GetWindowRect(m_impl->_hWnd, &rect); - if (width) - *width = rect.right - rect.left; - if (height) - *height = rect.bottom - rect.top; -} - -void InfiniFrameWindow::GetMaxSize(int* width, int* height) const { - if (width) - *width = m_impl->_maxWidth; - if (height) - *height = m_impl->_maxHeight; -} - -void InfiniFrameWindow::GetMinSize(int* width, int* height) const { - if (width) - *width = m_impl->_minWidth; - if (height) - *height = m_impl->_minHeight; -} - -AutoString InfiniFrameWindow::GetTitle() const { - return AllocateStringCopy(m_impl->_windowTitle); -} - -void InfiniFrameWindow::GetTopmost(bool* topmost) const { - // Return the stored intent rather than the live HWND style - *topmost = m_impl->_topmost; -} - -void InfiniFrameWindow::GetZoom(int* zoom) const { - if (zoom == nullptr) - return; - if (m_impl->_webviewController == nullptr) { - *zoom = m_impl->_zoom; - return; - } - - double rawValue = 0; - if (FAILED(m_impl->_webviewController->get_ZoomFactor(&rawValue))) { - *zoom = m_impl->_zoom; - return; - } - - rawValue = (rawValue * 100.0) + 0.5; //account for rounding issues - *zoom = static_cast(rawValue); -} - - -void InfiniFrameWindow::NavigateToString(AutoString content) { - std::wstring wideContent = ToUTF16String(content); - m_impl->_webviewWindow->NavigateToString(wideContent.c_str()); -} - -void InfiniFrameWindow::NavigateToUrl(AutoString url) { - std::wstring wideUrl = ToUTF16String(url); - m_impl->_webviewWindow->Navigate(wideUrl.c_str()); -} - -void InfiniFrameWindow::Restore() { - ShowWindow(m_impl->_hWnd, SW_RESTORE); -} - -void InfiniFrameWindow::SendWebMessage(AutoString message) { - if (!m_impl->_webviewWindow || !m_impl->_webviewController || !m_impl->_hWnd || !IsWindow(m_impl->_hWnd)) - return; - - std::wstring wideMessage = ToUTF16String(message); - m_impl->_webviewWindow->PostWebMessageAsString(wideMessage.c_str()); -} - - -void InfiniFrameWindow::SetTransparentEnabled(const bool enabled) { - m_impl->_transparentEnabled = enabled; - if (!m_impl->_webviewController || !m_impl->_webviewWindow) - return; - wil::com_ptr controller2; - if (FAILED(m_impl->_webviewController->QueryInterface(&controller2)) || !controller2) - return; - COREWEBVIEW2_COLOR backgroundColor; - controller2->get_DefaultBackgroundColor(&backgroundColor); - backgroundColor.A = enabled ? 0 : 255; - controller2->put_DefaultBackgroundColor(backgroundColor); - m_impl->_webviewWindow->Reload(); -} - -void InfiniFrameWindow::SetContextMenuEnabled(const bool enabled) { - m_impl->_contextMenuEnabled = enabled; - if (!m_impl->_webviewWindow) - return; - wil::com_ptr settings; - if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { - settings->put_AreDefaultContextMenusEnabled(enabled); - m_impl->_webviewWindow->Reload(); - } -} - -void InfiniFrameWindow::SetZoomEnabled(const bool enabled) { - m_impl->_zoomEnabled = enabled; - if (!m_impl->_webviewWindow) - return; - wil::com_ptr settings; - if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { - settings->put_IsZoomControlEnabled(enabled); - m_impl->_webviewWindow->Reload(); - } -} - -void InfiniFrameWindow::SetDevToolsEnabled(const bool enabled) { - m_impl->_devToolsEnabled = enabled; - if (!m_impl->_webviewWindow) - return; - wil::com_ptr settings; - if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { - settings->put_AreDevToolsEnabled(enabled); - m_impl->_webviewWindow->Reload(); - } -} - -void InfiniFrameWindow::SetFullScreen(const bool fullScreen) { - LONG_PTR style = GetWindowLongPtr(m_impl->_hWnd, GWL_STYLE); - if (fullScreen) { - GetWindowRect(m_impl->_hWnd, &m_impl->_savedRect); - m_impl->_hasSavedRect = true; - - style |= WS_POPUP; - style &= (~WS_OVERLAPPEDWINDOW); - SetWindowLongPtr(m_impl->_hWnd, GWL_STYLE, style); - - HMONITOR monitor = MonitorFromWindow(m_impl->_hWnd, MONITOR_DEFAULTTONEAREST); - MONITORINFO monitorInfo = {sizeof(monitorInfo)}; - - if (GetMonitorInfoW(monitor, &monitorInfo)) { - RECT rc = monitorInfo.rcMonitor; - SetWindowPos( - m_impl->_hWnd, HWND_TOP, - rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, - SWP_FRAMECHANGED | SWP_NOOWNERZORDER - ); - } - else { - SetWindowPos( - m_impl->_hWnd, HWND_TOP, - 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), - SWP_FRAMECHANGED | SWP_NOOWNERZORDER - ); - } - } - else { - style |= WS_OVERLAPPEDWINDOW; - style &= (~WS_POPUP); - SetWindowLongPtr(m_impl->_hWnd, GWL_STYLE, style); - - if (m_impl->_hasSavedRect) { - RECT& r = m_impl->_savedRect; - SetWindowPos( - m_impl->_hWnd, HWND_TOP, - r.left, r.top, r.right - r.left, r.bottom - r.top, - SWP_FRAMECHANGED | SWP_NOOWNERZORDER - ); - m_impl->_hasSavedRect = false; - } - } -} - -void InfiniFrameWindow::SetIconFile(const AutoString filename) { - std::wstring wideFilename = ToUTF16String(filename); - m_impl->_iconFileName = wideFilename; - if (wideFilename.empty()) - return; - - HICON iconSmall = static_cast(LoadImageW( - nullptr, wideFilename.c_str(), - IMAGE_ICON, 16, 16, - LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED - )); - HICON iconBig = static_cast(LoadImageW( - nullptr, wideFilename.c_str(), - IMAGE_ICON, 32, 32, - LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED - )); - - if (iconSmall && iconBig) { - SendMessageW(m_impl->_hWnd, WM_SETICON, ICON_SMALL, reinterpret_cast(iconSmall)); - SendMessageW(m_impl->_hWnd, WM_SETICON, ICON_BIG, reinterpret_cast(iconBig)); - } -} - -void InfiniFrameWindow::SetMinimized(const bool minimized) { - if (minimized) - ShowWindow(m_impl->_hWnd, SW_MINIMIZE); - else - ShowWindow(m_impl->_hWnd, SW_NORMAL); -} - -void InfiniFrameWindow::SetMinSize(const int width, const int height) { - m_impl->_minWidth = width; - m_impl->_minHeight = height; - - int currWidth, currHeight; - GetSize(&currWidth, &currHeight); - if (currWidth < m_impl->_minWidth) - SetSize(m_impl->_minWidth, currHeight); - if (currHeight < m_impl->_minHeight) - SetSize(currWidth, m_impl->_minHeight); -} - -void InfiniFrameWindow::SetMaximized(const bool maximized) { - if (maximized) - ShowWindow(m_impl->_hWnd, SW_MAXIMIZE); - else - ShowWindow(m_impl->_hWnd, SW_NORMAL); -} - -void InfiniFrameWindow::SetMaxSize(const int width, const int height) { - m_impl->_maxWidth = width; - m_impl->_maxHeight = height; - - int currWidth, currHeight; - GetSize(&currWidth, &currHeight); - if (currWidth > m_impl->_maxWidth) - SetSize(m_impl->_maxWidth, currHeight); - if (currHeight > m_impl->_maxHeight) - SetSize(currWidth, m_impl->_maxHeight); -} - -void InfiniFrameWindow::SetPosition(const int x, const int y) { - SetWindowPos(m_impl->_hWnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); -} - -void InfiniFrameWindow::SetResizable(const bool resizable) { - LONG_PTR style = GetWindowLongPtr(m_impl->_hWnd, GWL_STYLE); - if (resizable) - style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; - else - style &= (~WS_THICKFRAME) & (~WS_MINIMIZEBOX) & (~WS_MAXIMIZEBOX); - SetWindowLongPtr(m_impl->_hWnd, GWL_STYLE, style); -} - -void InfiniFrameWindow::SetSize(const int width, const int height) { - SetWindowPos(m_impl->_hWnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER); -} - -void InfiniFrameWindow::SetTitle(AutoString title) { - std::wstring wideTitle = ToUTF16String(title); - m_impl->_windowTitle = wideTitle; - SetWindowText(m_impl->_hWnd, wideTitle.c_str()); - if (m_impl->_notificationsEnabled) { - WinToast::instance()->setAppName(wideTitle.c_str()); - if (m_impl->_notificationRegistrationId.empty()) - WinToast::instance()->setAppUserModelId(wideTitle.c_str()); - } -} - -void InfiniFrameWindow::SetTopmost(const bool topmost) { - m_impl->_topmost = topmost; - LONG_PTR style = GetWindowLongPtr(m_impl->_hWnd, GWL_EXSTYLE); - if (topmost) - style |= WS_EX_TOPMOST; - else - style &= (~WS_EX_TOPMOST); - SetWindowLongPtr(m_impl->_hWnd, GWL_EXSTYLE, style); - SetWindowPos(m_impl->_hWnd, topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); -} - -void InfiniFrameWindow::SetZoom(const int zoom) { - if (zoom < 25 || zoom > 500) - return; - - m_impl->_zoom = zoom; - if (m_impl->_webviewController == nullptr) - return; - - const double newZoom = zoom / 100.0; - m_impl->_webviewController->put_ZoomFactor(newZoom); -} - -void InfiniFrameWindow::SetFocused() { - if (!m_impl->_hWnd) - return; - - // If minimized, restore first - if (IsIconic(m_impl->_hWnd)) - ShowWindow(m_impl->_hWnd, SW_RESTORE); - - // Try to request foreground rights - AllowSetForegroundWindow(ASFW_ANY); - - // Bring the window to the top and set focus/activation - HWND hwndForeground = GetForegroundWindow(); - const DWORD fgThread = hwndForeground ? GetWindowThreadProcessId(hwndForeground, nullptr) : 0; - const DWORD thisThread = GetCurrentThreadId(); - - // Temporarily attach thread inputs to improve the chances of success - if (fgThread && fgThread != thisThread) - AttachThreadInput(fgThread, thisThread, TRUE); - - ShowWindow(m_impl->_hWnd, SW_SHOW); - SetForegroundWindow(m_impl->_hWnd); - BringWindowToTop(m_impl->_hWnd); - SetActiveWindow(m_impl->_hWnd); - SetFocus(m_impl->_hWnd); - - if (fgThread && fgThread != thisThread) - AttachThreadInput(fgThread, thisThread, FALSE); - - // Also move focus to the embedded WebView2, if available - FocusWebView2(); -} - -void InfiniFrameWindow::ShowNotification(AutoString title, AutoString body) { - std::wstring wideTitle = ToUTF16String(title); - std::wstring wideBody = ToUTF16String(body); - if (m_impl->_notificationsEnabled && WinToast::isCompatible()) { - WinToastTemplate toast = WinToastTemplate(WinToastTemplate::ImageAndText02); - toast.setTextField(wideTitle.c_str(), WinToastTemplate::FirstLine); - toast.setTextField(wideBody.c_str(), WinToastTemplate::SecondLine); - if (!m_impl->_iconFileName.empty()) - toast.setImagePath(m_impl->_iconFileName); - WinToast::instance()->showToast(toast, m_impl->_toastHandler.get()); - } -} - void InfiniFrameWindow::WaitForExit() { ApplyPendingOwnerWindow(m_impl.get(), L"wait_for_exit"); @@ -1309,36 +777,6 @@ void InfiniFrameWindow::WaitForExit() { } -//Callbacks -BOOL MonitorEnum(const HMONITOR monitor, HDC, LPRECT, const LPARAM arg) { - auto callback = reinterpret_cast(arg); - UINT dpiX, dpiY; - MONITORINFO info = {}; - info.cbSize = sizeof(MONITORINFO); - GetMonitorInfo(monitor, &info); - GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); - Monitor props = {}; - props.monitor.x = info.rcMonitor.left; - props.monitor.y = info.rcMonitor.top; - props.monitor.width = info.rcMonitor.right - info.rcMonitor.left; - props.monitor.height = info.rcMonitor.bottom - info.rcMonitor.top; - props.work.x = info.rcWork.left; - props.work.y = info.rcWork.top; - props.work.width = info.rcWork.right - info.rcWork.left; - props.work.height = info.rcWork.bottom - info.rcWork.top; - props.scale = dpiY / 96.0; - return callback(&props) ? TRUE : FALSE; -} - -void InfiniFrameWindow::GetAllMonitors(GetAllMonitorsCallback callback) const { - if (callback) { - EnumDisplayMonitors( - nullptr, nullptr, reinterpret_cast(MonitorEnum), - reinterpret_cast(callback) - ); - } -} - void InfiniFrameWindow::Invoke(ACTION callback) { if (!callback) return; @@ -2158,105 +1596,3 @@ void InfiniFrameWindow::Show(const bool isAlreadyShown) { } } -// --------------------------------------------------------------------------------------------------------------------- -// Dialog and Scheme -// --------------------------------------------------------------------------------------------------------------------- - -InfiniFrameDialog* InfiniFrameWindow::GetDialog() const { - return m_impl->_dialog.get(); -} - -void InfiniFrameWindow::AddCustomSchemeName(const AutoStringConst scheme) { - if (scheme) - m_impl->_customSchemeNames.emplace_back(ToUTF16String(const_cast(scheme))); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Callback setters -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::SetClosingCallback(const ClosingCallback callback) { - m_impl->_closingCallback = callback; -} - -void InfiniFrameWindow::SetClosedCallback(const ClosedCallback callback) { - m_impl->_closedCallback = callback; -} - -void InfiniFrameWindow::SetFocusInCallback(const FocusInCallback callback) { - m_impl->_focusInCallback = callback; -} - -void InfiniFrameWindow::SetFocusOutCallback(const FocusOutCallback callback) { - m_impl->_focusOutCallback = callback; -} - -void InfiniFrameWindow::SetMovedCallback(const MovedCallback callback) { - m_impl->_movedCallback = callback; -} - -void InfiniFrameWindow::SetResizedCallback(const ResizedCallback callback) { - m_impl->_resizedCallback = callback; -} - -void InfiniFrameWindow::SetMaximizedCallback(const MaximizedCallback callback) { - m_impl->_maximizedCallback = callback; -} - -void InfiniFrameWindow::SetRestoredCallback(const RestoredCallback callback) { - m_impl->_restoredCallback = callback; -} - -void InfiniFrameWindow::SetMinimizedCallback(const MinimizedCallback callback) { - m_impl->_minimizedCallback = callback; -} - -// --------------------------------------------------------------------------------------------------------------------- -// Invoke callbacks -// --------------------------------------------------------------------------------------------------------------------- - -bool InfiniFrameWindow::InvokeClose() const noexcept { - if (m_impl->_closingCallback) - return m_impl->_closingCallback(); - return false; -} - -void InfiniFrameWindow::InvokeClosed() const noexcept { - if (!m_impl->_closedCallback) return; - m_impl->_closedCallback(); -} - -void InfiniFrameWindow::InvokeFocusIn() const noexcept { - if (m_impl->_focusInCallback) - m_impl->_focusInCallback(); -} - -void InfiniFrameWindow::InvokeFocusOut() const noexcept { - if (m_impl->_focusOutCallback) - m_impl->_focusOutCallback(); -} - -void InfiniFrameWindow::InvokeMove(int x, int y) const noexcept { - if (m_impl->_movedCallback) - m_impl->_movedCallback(x, y); -} - -void InfiniFrameWindow::InvokeResize(int width, int height) const noexcept { - if (m_impl->_resizedCallback) - m_impl->_resizedCallback(width, height); -} - -void InfiniFrameWindow::InvokeMaximized() const noexcept { - if (m_impl->_maximizedCallback) - m_impl->_maximizedCallback(); -} - -void InfiniFrameWindow::InvokeRestored() const noexcept { - if (m_impl->_restoredCallback) - m_impl->_restoredCallback(); -} - -void InfiniFrameWindow::InvokeMinimized() const noexcept { - if (m_impl->_minimizedCallback) - m_impl->_minimizedCallback(); -} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEvents.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEvents.Win32.cpp new file mode 100644 index 000000000..fa8d7fd9a --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEvents.Win32.cpp @@ -0,0 +1,137 @@ +#include "Window.Win32.Internal.h" + +#include + +BOOL MonitorEnum(const HMONITOR monitor, HDC, LPRECT, const LPARAM arg) { + auto callback = reinterpret_cast(arg); + UINT dpiX, dpiY; + MONITORINFO info = {}; + info.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(monitor, &info); + GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + Monitor props = {}; + props.monitor.x = info.rcMonitor.left; + props.monitor.y = info.rcMonitor.top; + props.monitor.width = info.rcMonitor.right - info.rcMonitor.left; + props.monitor.height = info.rcMonitor.bottom - info.rcMonitor.top; + props.work.x = info.rcWork.left; + props.work.y = info.rcWork.top; + props.work.width = info.rcWork.right - info.rcWork.left; + props.work.height = info.rcWork.bottom - info.rcWork.top; + props.scale = dpiY / 96.0; + return callback(&props) ? TRUE : FALSE; +} + +void InfiniFrameWindow::ShowNotification(AutoString title, AutoString body) { + std::wstring wideTitle = ToUTF16String(title); + std::wstring wideBody = ToUTF16String(body); + if (m_impl->_notificationsEnabled && WinToastLib::WinToast::isCompatible()) { + WinToastLib::WinToastTemplate toast = WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::ImageAndText02); + toast.setTextField(wideTitle.c_str(), WinToastLib::WinToastTemplate::FirstLine); + toast.setTextField(wideBody.c_str(), WinToastLib::WinToastTemplate::SecondLine); + if (!m_impl->_iconFileName.empty()) + toast.setImagePath(m_impl->_iconFileName); + WinToastLib::WinToast::instance()->showToast(toast, m_impl->_toastHandler.get()); + } +} + +void InfiniFrameWindow::GetAllMonitors(GetAllMonitorsCallback callback) const { + if (callback) { + EnumDisplayMonitors( + nullptr, nullptr, reinterpret_cast(MonitorEnum), + reinterpret_cast(callback) + ); + } +} + +InfiniFrameDialog* InfiniFrameWindow::GetDialog() const { + return m_impl->_dialog.get(); +} + +void InfiniFrameWindow::AddCustomSchemeName(const AutoStringConst scheme) { + if (scheme) + m_impl->_customSchemeNames.emplace_back(ToUTF16String(const_cast(scheme))); +} + +void InfiniFrameWindow::SetClosingCallback(const ClosingCallback callback) { + m_impl->_closingCallback = callback; +} + +void InfiniFrameWindow::SetClosedCallback(const ClosedCallback callback) { + m_impl->_closedCallback = callback; +} + +void InfiniFrameWindow::SetFocusInCallback(const FocusInCallback callback) { + m_impl->_focusInCallback = callback; +} + +void InfiniFrameWindow::SetFocusOutCallback(const FocusOutCallback callback) { + m_impl->_focusOutCallback = callback; +} + +void InfiniFrameWindow::SetMovedCallback(const MovedCallback callback) { + m_impl->_movedCallback = callback; +} + +void InfiniFrameWindow::SetResizedCallback(const ResizedCallback callback) { + m_impl->_resizedCallback = callback; +} + +void InfiniFrameWindow::SetMaximizedCallback(const MaximizedCallback callback) { + m_impl->_maximizedCallback = callback; +} + +void InfiniFrameWindow::SetRestoredCallback(const RestoredCallback callback) { + m_impl->_restoredCallback = callback; +} + +void InfiniFrameWindow::SetMinimizedCallback(const MinimizedCallback callback) { + m_impl->_minimizedCallback = callback; +} + +bool InfiniFrameWindow::InvokeClose() const noexcept { + if (m_impl->_closingCallback) + return m_impl->_closingCallback(); + return false; +} + +void InfiniFrameWindow::InvokeClosed() const noexcept { + if (!m_impl->_closedCallback) + return; + m_impl->_closedCallback(); +} + +void InfiniFrameWindow::InvokeFocusIn() const noexcept { + if (m_impl->_focusInCallback) + m_impl->_focusInCallback(); +} + +void InfiniFrameWindow::InvokeFocusOut() const noexcept { + if (m_impl->_focusOutCallback) + m_impl->_focusOutCallback(); +} + +void InfiniFrameWindow::InvokeMove(int x, int y) const noexcept { + if (m_impl->_movedCallback) + m_impl->_movedCallback(x, y); +} + +void InfiniFrameWindow::InvokeResize(int width, int height) const noexcept { + if (m_impl->_resizedCallback) + m_impl->_resizedCallback(width, height); +} + +void InfiniFrameWindow::InvokeMaximized() const noexcept { + if (m_impl->_maximizedCallback) + m_impl->_maximizedCallback(); +} + +void InfiniFrameWindow::InvokeRestored() const noexcept { + if (m_impl->_restoredCallback) + m_impl->_restoredCallback(); +} + +void InfiniFrameWindow::InvokeMinimized() const noexcept { + if (m_impl->_minimizedCallback) + m_impl->_minimizedCallback(); +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowState.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowState.Win32.cpp new file mode 100644 index 000000000..86d733134 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowState.Win32.cpp @@ -0,0 +1,462 @@ +#include "Window.Win32.Internal.h" + +#include + +#include "Utils/Common.h" + +void InfiniFrameWindow::Center() { + int screenDpi = GetDpiForWindow(m_impl->_hWnd); + int screenHeight = GetSystemMetricsForDpi(SM_CYSCREEN, screenDpi); + int screenWidth = GetSystemMetricsForDpi(SM_CXSCREEN, screenDpi); + + RECT windowRect = {}; + GetWindowRect(m_impl->_hWnd, &windowRect); + int windowHeight = windowRect.bottom - windowRect.top; + int windowWidth = windowRect.right - windowRect.left; + + int left = (screenWidth / 2) - (windowWidth / 2); + int top = (screenHeight / 2) - (windowHeight / 2); + + SetPosition(left, top); +} + +void InfiniFrameWindow::Close() { + PostMessage(m_impl->_hWnd, WM_CLOSE, 0, 0); +} + +void InfiniFrameWindow::GetTransparentEnabled(bool* enabled) const { + if (!m_impl->_webviewController) { + *enabled = m_impl->_transparentEnabled; + return; + } + wil::com_ptr controller2; + if (FAILED(m_impl->_webviewController->QueryInterface(&controller2)) || !controller2) { + *enabled = m_impl->_transparentEnabled; + return; + } + COREWEBVIEW2_COLOR backgroundColor; + controller2->get_DefaultBackgroundColor(&backgroundColor); + *enabled = backgroundColor.A == 0; +} + +void InfiniFrameWindow::GetContextMenuEnabled(bool* enabled) const { + if (!m_impl->_webviewWindow) { + *enabled = m_impl->_contextMenuEnabled; + return; + } + wil::com_ptr settings; + if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { + BOOL boolValue = FALSE; + settings->get_AreDefaultContextMenusEnabled(&boolValue); + *enabled = (boolValue != FALSE); + } +} + +void InfiniFrameWindow::GetZoomEnabled(bool* enabled) const { + if (!m_impl->_webviewWindow) { + *enabled = m_impl->_zoomEnabled; + return; + } + wil::com_ptr settings; + if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { + BOOL boolValue = FALSE; + settings->get_IsZoomControlEnabled(&boolValue); + *enabled = (boolValue != FALSE); + } +} + +void InfiniFrameWindow::GetDevToolsEnabled(bool* enabled) const { + if (!m_impl->_webviewWindow) { + *enabled = m_impl->_devToolsEnabled; + return; + } + wil::com_ptr settings; + if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { + BOOL boolValue = FALSE; + settings->get_AreDevToolsEnabled(&boolValue); + *enabled = (boolValue != FALSE); + } +} + +void InfiniFrameWindow::GetFullScreen(bool* fullScreen) const { + LONG lStyles = GetWindowLong(m_impl->_hWnd, GWL_STYLE); + *fullScreen = (lStyles & WS_POPUP) != 0; +} + +void InfiniFrameWindow::GetGrantBrowserPermissions(bool* grant) const { + *grant = m_impl->_grantBrowserPermissions; +} + +AutoString InfiniFrameWindow::GetUserAgent() const { + return AllocateStringCopy(m_impl->_userAgent); +} + +void InfiniFrameWindow::GetMediaAutoplayEnabled(bool* enabled) const { + *enabled = m_impl->_mediaAutoplayEnabled; +} + +void InfiniFrameWindow::GetFileSystemAccessEnabled(bool* enabled) const { + *enabled = m_impl->_fileSystemAccessEnabled; +} + +void InfiniFrameWindow::GetWebSecurityEnabled(bool* enabled) const { + *enabled = m_impl->_webSecurityEnabled; +} + +void InfiniFrameWindow::GetJavascriptClipboardAccessEnabled(bool* enabled) const { + *enabled = m_impl->_javascriptClipboardAccessEnabled; +} + +void InfiniFrameWindow::GetMediaStreamEnabled(bool* enabled) const { + *enabled = m_impl->_mediaStreamEnabled; +} + +void InfiniFrameWindow::GetSmoothScrollingEnabled(bool* enabled) const { + *enabled = m_impl->_smoothScrollingEnabled; +} + +void InfiniFrameWindow::GetIgnoreCertificateErrorsEnabled(bool* enabled) const { + *enabled = m_impl->_ignoreCertificateErrorsEnabled; +} + +void InfiniFrameWindow::GetFocused(bool* isFocused) const { + *isFocused = GetFocus() == m_impl->_hWnd; +} + +void InfiniFrameWindow::GetNotificationsEnabled(bool* enabled) const { + *enabled = m_impl->_notificationsEnabled; +} + +AutoString InfiniFrameWindow::GetIconFileName() const { + return AllocateStringCopy(m_impl->_iconFileName); +} + +void InfiniFrameWindow::GetMaximized(bool* isMaximized) const { + LONG lStyles = GetWindowLong(m_impl->_hWnd, GWL_STYLE); + *isMaximized = (lStyles & WS_MAXIMIZE) != 0; +} + +void InfiniFrameWindow::GetMinimized(bool* isMinimized) const { + LONG lStyles = GetWindowLong(m_impl->_hWnd, GWL_STYLE); + *isMinimized = (lStyles & WS_MINIMIZE) != 0; +} + +void InfiniFrameWindow::GetPosition(int* x, int* y) const { + RECT rect = {}; + GetWindowRect(m_impl->_hWnd, &rect); + if (x) + *x = rect.left; + if (y) + *y = rect.top; +} + +void InfiniFrameWindow::GetResizable(bool* resizable) const { + LONG lStyles = GetWindowLong(m_impl->_hWnd, GWL_STYLE); + *resizable = (lStyles & WS_THICKFRAME) != 0; +} + +unsigned int InfiniFrameWindow::GetScreenDpi() const { + return GetDpiForWindow(m_impl->_hWnd); +} + +void InfiniFrameWindow::GetSize(int* width, int* height) const { + RECT rect = {}; + GetWindowRect(m_impl->_hWnd, &rect); + if (width) + *width = rect.right - rect.left; + if (height) + *height = rect.bottom - rect.top; +} + +void InfiniFrameWindow::GetMaxSize(int* width, int* height) const { + if (width) + *width = m_impl->_maxWidth; + if (height) + *height = m_impl->_maxHeight; +} + +void InfiniFrameWindow::GetMinSize(int* width, int* height) const { + if (width) + *width = m_impl->_minWidth; + if (height) + *height = m_impl->_minHeight; +} + +AutoString InfiniFrameWindow::GetTitle() const { + return AllocateStringCopy(m_impl->_windowTitle); +} + +void InfiniFrameWindow::GetTopmost(bool* topmost) const { + *topmost = m_impl->_topmost; +} + +void InfiniFrameWindow::GetZoom(int* zoom) const { + if (zoom == nullptr) + return; + if (m_impl->_webviewController == nullptr) { + *zoom = m_impl->_zoom; + return; + } + + double rawValue = 0; + if (FAILED(m_impl->_webviewController->get_ZoomFactor(&rawValue))) { + *zoom = m_impl->_zoom; + return; + } + + rawValue = (rawValue * 100.0) + 0.5; + *zoom = static_cast(rawValue); +} + +void InfiniFrameWindow::NavigateToString(AutoString content) { + std::wstring wideContent = ToUTF16String(content); + m_impl->_webviewWindow->NavigateToString(wideContent.c_str()); +} + +void InfiniFrameWindow::NavigateToUrl(AutoString url) { + std::wstring wideUrl = ToUTF16String(url); + m_impl->_webviewWindow->Navigate(wideUrl.c_str()); +} + +void InfiniFrameWindow::Restore() { + ShowWindow(m_impl->_hWnd, SW_RESTORE); +} + +void InfiniFrameWindow::SendWebMessage(AutoString message) { + if (!m_impl->_webviewWindow || !m_impl->_webviewController || !m_impl->_hWnd || !IsWindow(m_impl->_hWnd)) + return; + + std::wstring wideMessage = ToUTF16String(message); + m_impl->_webviewWindow->PostWebMessageAsString(wideMessage.c_str()); +} + +void InfiniFrameWindow::SetTransparentEnabled(const bool enabled) { + m_impl->_transparentEnabled = enabled; + if (!m_impl->_webviewController || !m_impl->_webviewWindow) + return; + wil::com_ptr controller2; + if (FAILED(m_impl->_webviewController->QueryInterface(&controller2)) || !controller2) + return; + COREWEBVIEW2_COLOR backgroundColor; + controller2->get_DefaultBackgroundColor(&backgroundColor); + backgroundColor.A = enabled ? 0 : 255; + controller2->put_DefaultBackgroundColor(backgroundColor); + m_impl->_webviewWindow->Reload(); +} + +void InfiniFrameWindow::SetContextMenuEnabled(const bool enabled) { + m_impl->_contextMenuEnabled = enabled; + if (!m_impl->_webviewWindow) + return; + wil::com_ptr settings; + if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { + settings->put_AreDefaultContextMenusEnabled(enabled); + m_impl->_webviewWindow->Reload(); + } +} + +void InfiniFrameWindow::SetZoomEnabled(const bool enabled) { + m_impl->_zoomEnabled = enabled; + if (!m_impl->_webviewWindow) + return; + wil::com_ptr settings; + if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { + settings->put_IsZoomControlEnabled(enabled); + m_impl->_webviewWindow->Reload(); + } +} + +void InfiniFrameWindow::SetDevToolsEnabled(const bool enabled) { + m_impl->_devToolsEnabled = enabled; + if (!m_impl->_webviewWindow) + return; + wil::com_ptr settings; + if (SUCCEEDED(m_impl->_webviewWindow->get_Settings(&settings)) && settings) { + settings->put_AreDevToolsEnabled(enabled); + m_impl->_webviewWindow->Reload(); + } +} + +void InfiniFrameWindow::SetFullScreen(const bool fullScreen) { + LONG_PTR style = GetWindowLongPtr(m_impl->_hWnd, GWL_STYLE); + if (fullScreen) { + GetWindowRect(m_impl->_hWnd, &m_impl->_savedRect); + m_impl->_hasSavedRect = true; + + style |= WS_POPUP; + style &= (~WS_OVERLAPPEDWINDOW); + SetWindowLongPtr(m_impl->_hWnd, GWL_STYLE, style); + + HMONITOR monitor = MonitorFromWindow(m_impl->_hWnd, MONITOR_DEFAULTTONEAREST); + MONITORINFO monitorInfo = {sizeof(monitorInfo)}; + + if (GetMonitorInfoW(monitor, &monitorInfo)) { + RECT rc = monitorInfo.rcMonitor; + SetWindowPos( + m_impl->_hWnd, HWND_TOP, + rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, + SWP_FRAMECHANGED | SWP_NOOWNERZORDER + ); + } else { + SetWindowPos( + m_impl->_hWnd, HWND_TOP, + 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), + SWP_FRAMECHANGED | SWP_NOOWNERZORDER + ); + } + } else { + style |= WS_OVERLAPPEDWINDOW; + style &= (~WS_POPUP); + SetWindowLongPtr(m_impl->_hWnd, GWL_STYLE, style); + + if (m_impl->_hasSavedRect) { + RECT& r = m_impl->_savedRect; + SetWindowPos( + m_impl->_hWnd, HWND_TOP, + r.left, r.top, r.right - r.left, r.bottom - r.top, + SWP_FRAMECHANGED | SWP_NOOWNERZORDER + ); + m_impl->_hasSavedRect = false; + } + } +} + +void InfiniFrameWindow::SetIconFile(const AutoString filename) { + std::wstring wideFilename = ToUTF16String(filename); + m_impl->_iconFileName = wideFilename; + if (wideFilename.empty()) + return; + + HICON iconSmall = static_cast(LoadImageW( + nullptr, wideFilename.c_str(), + IMAGE_ICON, 16, 16, + LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED + )); + HICON iconBig = static_cast(LoadImageW( + nullptr, wideFilename.c_str(), + IMAGE_ICON, 32, 32, + LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED + )); + + if (iconSmall && iconBig) { + SendMessageW(m_impl->_hWnd, WM_SETICON, ICON_SMALL, reinterpret_cast(iconSmall)); + SendMessageW(m_impl->_hWnd, WM_SETICON, ICON_BIG, reinterpret_cast(iconBig)); + } +} + +void InfiniFrameWindow::SetMinimized(const bool minimized) { + if (minimized) + ShowWindow(m_impl->_hWnd, SW_MINIMIZE); + else + ShowWindow(m_impl->_hWnd, SW_NORMAL); +} + +void InfiniFrameWindow::SetMinSize(const int width, const int height) { + m_impl->_minWidth = width; + m_impl->_minHeight = height; + + int currWidth, currHeight; + GetSize(&currWidth, &currHeight); + if (currWidth < m_impl->_minWidth) + SetSize(m_impl->_minWidth, currHeight); + if (currHeight < m_impl->_minHeight) + SetSize(currWidth, m_impl->_minHeight); +} + +void InfiniFrameWindow::SetMaximized(const bool maximized) { + if (maximized) + ShowWindow(m_impl->_hWnd, SW_MAXIMIZE); + else + ShowWindow(m_impl->_hWnd, SW_NORMAL); +} + +void InfiniFrameWindow::SetMaxSize(const int width, const int height) { + m_impl->_maxWidth = width; + m_impl->_maxHeight = height; + + int currWidth, currHeight; + GetSize(&currWidth, &currHeight); + if (currWidth > m_impl->_maxWidth) + SetSize(m_impl->_maxWidth, currHeight); + if (currHeight > m_impl->_maxHeight) + SetSize(currWidth, m_impl->_maxHeight); +} + +void InfiniFrameWindow::SetPosition(const int x, const int y) { + SetWindowPos(m_impl->_hWnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +void InfiniFrameWindow::SetResizable(const bool resizable) { + LONG_PTR style = GetWindowLongPtr(m_impl->_hWnd, GWL_STYLE); + if (resizable) + style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + else + style &= (~WS_THICKFRAME) & (~WS_MINIMIZEBOX) & (~WS_MAXIMIZEBOX); + SetWindowLongPtr(m_impl->_hWnd, GWL_STYLE, style); +} + +void InfiniFrameWindow::SetSize(const int width, const int height) { + SetWindowPos(m_impl->_hWnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER); +} + +void InfiniFrameWindow::SetTitle(AutoString title) { + std::wstring wideTitle = ToUTF16String(title); + m_impl->_windowTitle = wideTitle; + SetWindowText(m_impl->_hWnd, wideTitle.c_str()); + if (m_impl->_notificationsEnabled) { + WinToastLib::WinToast::instance()->setAppName(wideTitle.c_str()); + if (m_impl->_notificationRegistrationId.empty()) + WinToastLib::WinToast::instance()->setAppUserModelId(wideTitle.c_str()); + } +} + +void InfiniFrameWindow::SetTopmost(const bool topmost) { + m_impl->_topmost = topmost; + LONG_PTR style = GetWindowLongPtr(m_impl->_hWnd, GWL_EXSTYLE); + if (topmost) + style |= WS_EX_TOPMOST; + else + style &= (~WS_EX_TOPMOST); + SetWindowLongPtr(m_impl->_hWnd, GWL_EXSTYLE, style); + SetWindowPos(m_impl->_hWnd, topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); +} + +void InfiniFrameWindow::SetZoom(const int zoom) { + if (zoom < 25 || zoom > 500) + return; + + m_impl->_zoom = zoom; + if (m_impl->_webviewController == nullptr) + return; + + const double newZoom = zoom / 100.0; + m_impl->_webviewController->put_ZoomFactor(newZoom); +} + +void InfiniFrameWindow::SetFocused() { + if (!m_impl->_hWnd) + return; + + if (IsIconic(m_impl->_hWnd)) + ShowWindow(m_impl->_hWnd, SW_RESTORE); + + AllowSetForegroundWindow(ASFW_ANY); + + HWND hwndForeground = GetForegroundWindow(); + const DWORD fgThread = hwndForeground ? GetWindowThreadProcessId(hwndForeground, nullptr) : 0; + const DWORD thisThread = GetCurrentThreadId(); + + if (fgThread && fgThread != thisThread) + AttachThreadInput(fgThread, thisThread, TRUE); + + ShowWindow(m_impl->_hWnd, SW_SHOW); + SetForegroundWindow(m_impl->_hWnd); + BringWindowToTop(m_impl->_hWnd); + SetActiveWindow(m_impl->_hWnd); + SetFocus(m_impl->_hWnd); + + if (fgThread && fgThread != thisThread) + AttachThreadInput(fgThread, thisThread, FALSE); + + FocusWebView2(); +} From 41befa52f84e82154349b7b4b33768b58e43e618 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 18:38:31 +0200 Subject: [PATCH 03/86] Add cross-platform UI dispatcher and WebView bridge components for Linux (GTK/WebKit) and Windows (Win32/WebView2). --- .../Native/CMakeLists.txt | 8 + .../Platform/Linux/UiDispatcher.Gtk.cpp | 42 + .../Platform/Linux/WebKitBridge.Gtk.cpp | 287 +++ .../Native/Platform/Linux/Window.cpp | 498 +---- .../Platform/Linux/WindowSignals.Gtk.cpp | 184 ++ .../Platform/Windows/UiDispatcher.Win32.cpp | 47 + .../Platform/Windows/WebView2Host.Win32.cpp | 826 +++++++++ .../Platform/Windows/Window.Win32.Context.h | 91 + .../Native/Platform/Windows/Window.cpp | 1602 ++--------------- .../Windows/WindowLifecycle.Win32.cpp | 264 +++ .../Platform/Windows/WindowProc.Win32.cpp | 151 ++ 11 files changed, 2003 insertions(+), 1997 deletions(-) create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/UiDispatcher.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitBridge.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowSignals.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowLifecycle.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowProc.Win32.cpp diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index 6b2d4b1f3..9daa3ebb2 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -46,8 +46,12 @@ set(TEST_SOURCES set(WINDOWS_SOURCES Platform/Windows/Window.cpp + Platform/Windows/WindowLifecycle.Win32.cpp + Platform/Windows/WindowProc.Win32.cpp Platform/Windows/WindowState.Win32.cpp Platform/Windows/WindowEvents.Win32.cpp + Platform/Windows/WebView2Host.Win32.cpp + Platform/Windows/UiDispatcher.Win32.cpp Platform/Windows/DarkMode.cpp Platform/Windows/Dialog.cpp ) @@ -57,6 +61,9 @@ set(LINUX_SOURCES Platform/Linux/WindowLifecycle.Gtk.cpp Platform/Linux/WindowState.Gtk.cpp Platform/Linux/WindowEvents.Gtk.cpp + Platform/Linux/UiDispatcher.Gtk.cpp + Platform/Linux/WebKitBridge.Gtk.cpp + Platform/Linux/WindowSignals.Gtk.cpp Platform/Linux/Dialog.cpp ) @@ -89,6 +96,7 @@ set(HEADER_FILES Exports/Exports.Shared.h Platform/Windows/ToastHandler.h Platform/Windows/Window.Win32.Internal.h + Platform/Windows/Window.Win32.Context.h Platform/Windows/DarkMode.h Platform/Mac/AppDelegate.h Platform/Mac/NavigationDelegate.h diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/UiDispatcher.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/UiDispatcher.Gtk.cpp new file mode 100644 index 000000000..b13a74fb6 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/UiDispatcher.Gtk.cpp @@ -0,0 +1,42 @@ +#ifdef __linux__ + +#include +#include + +#include "Window.Gtk.Internal.h" + +namespace { + std::mutex invokeLockMutex; + + struct InvokeWaitInfo { + ACTION callback; + std::condition_variable completionNotifier; + bool isCompleted; + }; + + gboolean invokeCallback(const gpointer data) { + auto* waitInfo = reinterpret_cast(data); + waitInfo->callback(); + { + std::lock_guard guard(invokeLockMutex); + waitInfo->isCompleted = true; + } + waitInfo->completionNotifier.notify_one(); + return false; + } +} + +void InfiniFrameWindow::Invoke(const ACTION callback) { + InvokeWaitInfo waitInfo = {}; + waitInfo.callback = callback; + gdk_threads_add_idle(invokeCallback, &waitInfo); + + std::unique_lock uLock(invokeLockMutex); + waitInfo.completionNotifier.wait( + uLock, [&] { + return waitInfo.isCompleted; + } + ); +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitBridge.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitBridge.Gtk.cpp new file mode 100644 index 000000000..cdd879d5b --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitBridge.Gtk.cpp @@ -0,0 +1,287 @@ +#ifdef __linux__ + +#include +#include + +#include +#include +#include + +#include "Embedded/Embedded.h" +#include "Window.Gtk.Internal.h" + +extern void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data); +extern gboolean on_webview_load_failed( + WebKitWebView* web_view, + WebKitLoadEvent load_event, + gchar* failing_uri, + GError* error, + gpointer user_data + ); +extern void on_webview_process_terminated( + WebKitWebView* web_view, + WebKitWebProcessTerminationReason reason, + gpointer user_data + ); +extern void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data); + +namespace { + void HandleWebMessage( + WebKitUserContentManager* contentManager, + WebKitJavascriptResult* jsResult, + const gpointer userData + ) { + JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); + if (jsc_value_is_string(jsValue)) { + AutoString str_value = jsc_value_to_string(jsValue); + WebMessageReceivedCallback callback = reinterpret_cast(userData); + AutoString originValue = nullptr; + + JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); + JSStringRef script = JSStringCreateWithUTF8CString("window.location.href"); + JSValueRef locationValue = JSEvaluateScript(context, script, nullptr, nullptr, 0, nullptr); + JSStringRelease(script); + + if (locationValue != nullptr) { + JSStringRef locationString = JSValueToStringCopy(context, locationValue, nullptr); + if (locationString != nullptr) { + size_t maxBytes = JSStringGetMaximumUTF8CStringSize(locationString); + originValue = static_cast(g_malloc(maxBytes)); + JSStringGetUTF8CString(locationString, originValue, maxBytes); + JSStringRelease(locationString); + } + } + + if (callback != nullptr) { + callback(str_value, originValue); + } + + if (originValue != nullptr) + g_free(originValue); + + g_free(str_value); + } + webkit_javascript_result_unref(jsResult); + } + + void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { + WebResourceRequestedCallback webResourceRequestedCallback = reinterpret_cast( + user_data); + if (webResourceRequestedCallback == nullptr) { + GError* error = g_error_new_literal( + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "No custom scheme handler is registered."); + webkit_uri_scheme_request_finish_error(request, error); + g_error_free(error); + return; + } + + const gchar* uri = webkit_uri_scheme_request_get_uri(request); + int numBytes = 0; + AutoString contentType = nullptr; + void* dotNetResponse = webResourceRequestedCallback(const_cast(uri), &numBytes, &contentType); + GInputStream* stream = g_memory_input_stream_new_from_data(dotNetResponse, numBytes, nullptr); + webkit_uri_scheme_request_finish(request, reinterpret_cast(stream), -1, contentType); + g_object_unref(stream); + free(contentType); + } +} + +void InfiniFrameWindow::Impl::set_webkit_settings() { + WebKitSettings* settings = webkit_settings_new_with_settings( + "allow_modal_dialogs", TRUE, + "allow_top_navigation_to_data_urls", TRUE, + "allow_universal_access_from_file_urls", TRUE, + "enable_back_forward_navigation_gestures", TRUE, + "enable_media_capabilities", TRUE, + "enable_mock_capture_devices", TRUE, + "enable_page_cache", TRUE, + "enable_webrtc", TRUE, + "javascript_can_open_windows_automatically", TRUE, + + "allow_file_access_from_file_urls", _fileSystemAccessEnabled, + "disable_web_security", !_webSecurityEnabled, + "enable_developer_extras", _devToolsEnabled, + "enable_media_stream", _mediaStreamEnabled, + "enable_smooth_scrolling", _smoothScrollingEnabled, + "javascript_can_access_clipboard", _javascriptClipboardAccessEnabled, + "media_playback_requires_user_gesture", !_mediaAutoplayEnabled, + "user_agent", _userAgent.c_str(), + + NULL + ); + + if (!_browserControlInitParameters.empty()) + set_webkit_customsettings(settings); + + WebKitWebsiteDataManager* manager = webkit_web_view_get_website_data_manager(WEBKIT_WEB_VIEW(_webview)); + if (_ignoreCertificateErrorsEnabled) + webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_IGNORE); + else + webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_FAIL); + + webkit_web_view_set_settings(WEBKIT_WEB_VIEW(_webview), settings); +} + +void InfiniFrameWindow::Impl::set_webkit_customsettings(WebKitSettings* settings) { + try { + simdjson::ondemand::parser parser; + auto padded = simdjson::padded_string(_browserControlInitParameters); + auto doc = parser.iterate(padded); + + for (auto field : doc.get_object()) { + std::string_view keyView = field.unescaped_key(); + auto value = field.value(); + + gchar* propertyName = g_strdup(std::string(keyView).c_str()); + GValue propertyValue = G_VALUE_INIT; + bool hasValidValue = false; + + switch (value.type()) { + case simdjson::ondemand::json_type::string: { + std::string_view strVal; + if (value.get(strVal) == simdjson::SUCCESS) { + g_value_init(&propertyValue, G_TYPE_STRING); + g_value_set_string(&propertyValue, std::string(strVal).c_str()); + hasValidValue = true; + } + break; + } + case simdjson::ondemand::json_type::boolean: { + bool boolVal; + if (value.get(boolVal) == simdjson::SUCCESS) { + g_value_init(&propertyValue, G_TYPE_BOOLEAN); + g_value_set_boolean(&propertyValue, boolVal); + hasValidValue = true; + } + break; + } + case simdjson::ondemand::json_type::number: { + int64_t intVal; + if (value.get(intVal) == simdjson::SUCCESS) { + g_value_init(&propertyValue, G_TYPE_INT); + g_value_set_int(&propertyValue, static_cast(intVal)); + hasValidValue = true; + } + else { + double doubleVal; + if (value.get(doubleVal) == simdjson::SUCCESS) { + g_value_init(&propertyValue, G_TYPE_DOUBLE); + g_value_set_double(&propertyValue, doubleVal); + hasValidValue = true; + } + } + break; + } + default: + break; + } + + if (hasValidValue) { + g_object_set_property(G_OBJECT(settings), propertyName, &propertyValue); + g_value_unset(&propertyValue); + } + + g_free(propertyName); + } + } + catch (const simdjson::simdjson_error&) { + } +} + +void InfiniFrameWindow::Impl::AddCustomSchemeHandlers() { + if (_customSchemeCallback == nullptr) + return; + + WebKitWebContext* context = webkit_web_context_get_default(); + WebKitSecurityManager* securityManager = webkit_web_context_get_security_manager(context); + for (const auto& value : _customSchemeNames) { + if (securityManager != nullptr && g_ascii_strcasecmp(value.c_str(), "app") == 0) { + webkit_security_manager_register_uri_scheme_as_secure(securityManager, value.c_str()); + } + + webkit_web_context_register_uri_scheme( + context, value.c_str(), + reinterpret_cast(HandleCustomSchemeRequest), + reinterpret_cast(_customSchemeCallback), + nullptr + ); + } +} + +void InfiniFrameWindow::Show(bool isAlreadyShown) { + if (!m_impl->_webview) { + struct sigaction old_action; + sigaction(SIGCHLD, nullptr, &old_action); + WebKitUserContentManager* contentManager = webkit_user_content_manager_new(); + m_impl->_webview = webkit_web_view_new_with_user_content_manager(contentManager); + + m_impl->set_webkit_settings(); + + gtk_container_add(GTK_CONTAINER(m_impl->_window), m_impl->_webview); + gtk_widget_set_hexpand(m_impl->_webview, TRUE); + gtk_widget_set_vexpand(m_impl->_webview, TRUE); + + auto js = Embedded::InfiniFrameJsUtf8(); + + WebKitUserScript* script = webkit_user_script_new( + js.c_str(), + WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, + WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, + nullptr, + nullptr + ); + + webkit_user_content_manager_add_script(contentManager, script); + webkit_user_script_unref(script); + + g_signal_connect( + contentManager, "script-message-received::infiniFrameInterop", + G_CALLBACK(HandleWebMessage), + reinterpret_cast(m_impl->_webMessageReceivedCallback) + ); + webkit_user_content_manager_register_script_message_handler(contentManager, "infiniFrameInterop"); + + g_signal_connect( + G_OBJECT(m_impl->_webview), "load-changed", + G_CALLBACK(on_webview_load_changed), this + ); + g_signal_connect( + G_OBJECT(m_impl->_webview), "load-failed", + G_CALLBACK(on_webview_load_failed), this + ); + g_signal_connect( + G_OBJECT(m_impl->_webview), "web-process-terminated", + G_CALLBACK(on_webview_process_terminated), this + ); + g_signal_connect( + G_OBJECT(m_impl->_webview), "size-allocate", + G_CALLBACK(on_webview_size_allocate), this + ); + + if (!m_impl->_startUrl.empty()) + NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); + else if (!m_impl->_startString.empty()) + NavigateToString(const_cast(m_impl->_startString.c_str())); + else { + GtkWidget* dialog = gtk_message_dialog_new( + nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "Neither StartUrl nor StartString was specified" + ); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + sigaction(SIGCHLD, &old_action, nullptr); + return; + } + sigaction(SIGCHLD, &old_action, nullptr); + } + + gtk_widget_show_all(m_impl->_window); +} + +void InfiniFrameWindow::AttachWebView() { + // On Linux, WebView is attached in Show() +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp index 8d6f88ac5..c96551195 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp @@ -4,27 +4,12 @@ #include "Utils/Common.h" #include "Window.Gtk.Internal.h" #include -#include -#include #include -#include -#include -#include #include #include #include #include -#include -#include -#include "Embedded/Embedded.h" - -std::mutex invokeLockMutex; - -struct InvokeWaitInfo { - ACTION callback; - std::condition_variable completionNotifier; - bool isCompleted; -}; +#include // Forward declarations for GTK signal handlers gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, gpointer self); @@ -56,246 +41,6 @@ void on_webview_process_terminated( ); void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data); -// --------------------------------------------------------------------------------------------------------------------- -// Static signal handlers and helpers -// --------------------------------------------------------------------------------------------------------------------- - -static gboolean invokeCallback(const gpointer data) { - auto* waitInfo = reinterpret_cast(data); - waitInfo->callback(); - { - std::lock_guard guard(invokeLockMutex); - waitInfo->isCompleted = true; - } - waitInfo->completionNotifier.notify_one(); - return false; -} - -static void HandleWebMessage( - WebKitUserContentManager* contentManager, - WebKitJavascriptResult* jsResult, - const gpointer userData - ) { - JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); - if (jsc_value_is_string(jsValue)) { - AutoString str_value = jsc_value_to_string(jsValue); - WebMessageReceivedCallback callback = reinterpret_cast(userData); - AutoString originValue = nullptr; - - JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); - JSStringRef script = JSStringCreateWithUTF8CString("window.location.href"); - JSValueRef locationValue = JSEvaluateScript(context, script, nullptr, nullptr, 0, nullptr); - JSStringRelease(script); - - if (locationValue != nullptr) { - JSStringRef locationString = JSValueToStringCopy(context, locationValue, nullptr); - if (locationString != nullptr) { - size_t maxBytes = JSStringGetMaximumUTF8CStringSize(locationString); - originValue = static_cast(g_malloc(maxBytes)); - JSStringGetUTF8CString(locationString, originValue, maxBytes); - JSStringRelease(locationString); - } - } - - if (callback != nullptr) { - callback(str_value, originValue); - } - - if (originValue != nullptr) - g_free(originValue); - - g_free(str_value); - } - webkit_javascript_result_unref(jsResult); -} - -static void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { - WebResourceRequestedCallback webResourceRequestedCallback = reinterpret_cast( - user_data); - if (webResourceRequestedCallback == nullptr) { - GError* error = g_error_new_literal( - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "No custom scheme handler is registered."); - webkit_uri_scheme_request_finish_error(request, error); - g_error_free(error); - return; - } - - const gchar* uri = webkit_uri_scheme_request_get_uri(request); - int numBytes = 0; - AutoString contentType = nullptr; - void* dotNetResponse = webResourceRequestedCallback(const_cast(uri), &numBytes, &contentType); - GInputStream* stream = g_memory_input_stream_new_from_data(dotNetResponse, numBytes, nullptr); - webkit_uri_scheme_request_finish(request, reinterpret_cast(stream), -1, contentType); - g_object_unref(stream); - free(contentType); -} - -static bool linux_webview_diagnostics_enabled() { - const char* value = g_getenv("INFINIFRAME_LINUX_WEBVIEW_DIAGNOSTICS"); - return value != nullptr && value[0] != '\0' && g_strcmp0(value, "0") != 0; -} - -static const char* webkit_load_event_to_string(WebKitLoadEvent event) { - switch (event) { - case WEBKIT_LOAD_STARTED: - return "started"; - case WEBKIT_LOAD_REDIRECTED: - return "redirected"; - case WEBKIT_LOAD_COMMITTED: - return "committed"; - case WEBKIT_LOAD_FINISHED: - return "finished"; - default: - return "unknown"; - } -} - -static const char* webkit_termination_reason_to_string(WebKitWebProcessTerminationReason reason) { - switch (reason) { - case WEBKIT_WEB_PROCESS_CRASHED: - return "crashed"; - case WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: - return "exceeded-memory-limit"; - case WEBKIT_WEB_PROCESS_TERMINATED_BY_API: - return "terminated-by-api"; - default: - return "unknown"; - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// Impl method definitions -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::Impl::set_webkit_settings() { - WebKitSettings* settings = webkit_settings_new_with_settings( - "allow_modal_dialogs", TRUE, - "allow_top_navigation_to_data_urls", TRUE, - "allow_universal_access_from_file_urls", TRUE, - "enable_back_forward_navigation_gestures", TRUE, - "enable_media_capabilities", TRUE, - "enable_mock_capture_devices", TRUE, - "enable_page_cache", TRUE, - "enable_webrtc", TRUE, - "javascript_can_open_windows_automatically", TRUE, - - "allow_file_access_from_file_urls", _fileSystemAccessEnabled, - "disable_web_security", !_webSecurityEnabled, - "enable_developer_extras", _devToolsEnabled, - "enable_media_stream", _mediaStreamEnabled, - "enable_smooth_scrolling", _smoothScrollingEnabled, - "javascript_can_access_clipboard", _javascriptClipboardAccessEnabled, - "media_playback_requires_user_gesture", !_mediaAutoplayEnabled, - "user_agent", _userAgent.c_str(), - - NULL - ); - - if (!_browserControlInitParameters.empty()) - set_webkit_customsettings(settings); - - WebKitWebsiteDataManager* manager = webkit_web_view_get_website_data_manager(WEBKIT_WEB_VIEW(_webview)); - if (_ignoreCertificateErrorsEnabled) - webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_IGNORE); - else - webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_FAIL); - - webkit_web_view_set_settings(WEBKIT_WEB_VIEW(_webview), settings); -} - -void InfiniFrameWindow::Impl::set_webkit_customsettings(WebKitSettings* settings) { - try { - simdjson::ondemand::parser parser; - auto padded = simdjson::padded_string(_browserControlInitParameters); - auto doc = parser.iterate(padded); - - for (auto field : doc.get_object()) { - std::string_view keyView = field.unescaped_key(); - auto value = field.value(); - - gchar* propertyName = g_strdup(std::string(keyView).c_str()); - GValue propertyValue = G_VALUE_INIT; - bool hasValidValue = false; - - switch (value.type()) { - case simdjson::ondemand::json_type::string: { - std::string_view strVal; - if (value.get(strVal) == simdjson::SUCCESS) { - g_value_init(&propertyValue, G_TYPE_STRING); - g_value_set_string(&propertyValue, std::string(strVal).c_str()); - hasValidValue = true; - } - break; - } - case simdjson::ondemand::json_type::boolean: { - bool boolVal; - if (value.get(boolVal) == simdjson::SUCCESS) { - g_value_init(&propertyValue, G_TYPE_BOOLEAN); - g_value_set_boolean(&propertyValue, boolVal); - hasValidValue = true; - } - break; - } - case simdjson::ondemand::json_type::number: { - int64_t intVal; - if (value.get(intVal) == simdjson::SUCCESS) { - g_value_init(&propertyValue, G_TYPE_INT); - g_value_set_int(&propertyValue, static_cast(intVal)); - hasValidValue = true; - } - else { - double doubleVal; - if (value.get(doubleVal) == simdjson::SUCCESS) { - g_value_init(&propertyValue, G_TYPE_DOUBLE); - g_value_set_double(&propertyValue, doubleVal); - hasValidValue = true; - } - } - break; - } - default: - // Ignore unsupported JSON value types instead of crashing. - break; - } - - if (hasValidValue) { - g_object_set_property(G_OBJECT(settings), propertyName, &propertyValue); - g_value_unset(&propertyValue); - } - - g_free(propertyName); - } - } - catch (const simdjson::simdjson_error&) { - // Some callers pass CLI-like strings (e.g. --remote-debugging-port=9222). - // Ignore non-JSON payloads instead of aborting the process. - } -} - -void InfiniFrameWindow::Impl::AddCustomSchemeHandlers() { - if (_customSchemeCallback == nullptr) - return; - - WebKitWebContext* context = webkit_web_context_get_default(); - WebKitSecurityManager* securityManager = webkit_web_context_get_security_manager(context); - for (const auto& value : _customSchemeNames) { - if (securityManager != nullptr && g_ascii_strcasecmp(value.c_str(), "app") == 0) { - // Mirror Windows behavior for embedded static assets: - // only app:// is explicitly treated as a secure custom scheme. - webkit_security_manager_register_uri_scheme_as_secure(securityManager, value.c_str()); - } - - webkit_web_context_register_uri_scheme( - context, value.c_str(), - reinterpret_cast(HandleCustomSchemeRequest), - reinterpret_cast(_customSchemeCallback), - nullptr - ); - } -} - // --------------------------------------------------------------------------------------------------------------------- // Constructor / Destructor // --------------------------------------------------------------------------------------------------------------------- @@ -484,245 +229,4 @@ InfiniFrameWindow::~InfiniFrameWindow() { gtk_widget_destroy(m_impl->_window); } -// --------------------------------------------------------------------------------------------------------------------- -// Window Operations -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::Invoke(const ACTION callback) { - InvokeWaitInfo waitInfo = {}; - waitInfo.callback = callback; - gdk_threads_add_idle(invokeCallback, &waitInfo); - - std::unique_lock uLock(invokeLockMutex); - waitInfo.completionNotifier.wait( - uLock, [&] { - return waitInfo.isCompleted; - } - ); -} - -// --------------------------------------------------------------------------------------------------------------------- -// Private methods -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::Show(bool isAlreadyShown) { - if (!m_impl->_webview) { - struct sigaction old_action; - sigaction(SIGCHLD, nullptr, &old_action); - WebKitUserContentManager* contentManager = webkit_user_content_manager_new(); - m_impl->_webview = webkit_web_view_new_with_user_content_manager(contentManager); - - m_impl->set_webkit_settings(); - - gtk_container_add(GTK_CONTAINER(m_impl->_window), m_impl->_webview); - gtk_widget_set_hexpand(m_impl->_webview, TRUE); - gtk_widget_set_vexpand(m_impl->_webview, TRUE); - - auto js = Embedded::InfiniFrameJsUtf8(); - - WebKitUserScript* script = webkit_user_script_new( - js.c_str(), - WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, - WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, - nullptr, - nullptr - ); - - webkit_user_content_manager_add_script(contentManager, script); - webkit_user_script_unref(script); - - g_signal_connect( - contentManager, "script-message-received::infiniFrameInterop", - G_CALLBACK(HandleWebMessage), - reinterpret_cast(m_impl->_webMessageReceivedCallback) - ); - webkit_user_content_manager_register_script_message_handler(contentManager, "infiniFrameInterop"); - - g_signal_connect( - G_OBJECT(m_impl->_webview), "load-changed", - G_CALLBACK(on_webview_load_changed), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "load-failed", - G_CALLBACK(on_webview_load_failed), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "web-process-terminated", - G_CALLBACK(on_webview_process_terminated), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "size-allocate", - G_CALLBACK(on_webview_size_allocate), this - ); - - if (!m_impl->_startUrl.empty()) - NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); - else if (!m_impl->_startString.empty()) - NavigateToString(const_cast(m_impl->_startString.c_str())); - else { - GtkWidget* dialog = gtk_message_dialog_new( - nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "Neither StartUrl nor StartString was specified" - ); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - sigaction(SIGCHLD, &old_action, nullptr); - return; - } - sigaction(SIGCHLD, &old_action, nullptr); - } - - gtk_widget_show_all(m_impl->_window); -} - -void InfiniFrameWindow::AttachWebView() { - // On Linux, WebView is attached in Show() -} - -void InfiniFrameWindow::OnConfigureEvent(int x, int y, int width, int height) { - if (m_impl->_lastLeft != x || m_impl->_lastTop != y) { - InvokeMove(x, y); - m_impl->_lastLeft = x; - m_impl->_lastTop = y; - } - - if (m_impl->_lastHeight != height || m_impl->_lastWidth != width) { - InvokeResize(width, height); - m_impl->_lastWidth = width; - m_impl->_lastHeight = height; - } -} - -void InfiniFrameWindow::OnWindowStateEvent(GdkWindowState newState) { - if (newState & GDK_WINDOW_STATE_MAXIMIZED) { - InvokeMaximized(); - } - else if ((newState & GDK_WINDOW_STATE_ICONIFIED) || !gtk_widget_get_mapped(m_impl->_window)) { - InvokeMinimized(); - } - else if (!(newState & GDK_WINDOW_STATE_MAXIMIZED) && !(newState & GDK_WINDOW_STATE_ICONIFIED)) { - InvokeRestored(); - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// GTK Signal Handlers -// --------------------------------------------------------------------------------------------------------------------- - -gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, const gpointer self) { - if (event->type == GDK_CONFIGURE) { - auto* instance = reinterpret_cast(self); - instance->OnConfigureEvent( - event->configure.x, event->configure.y, - event->configure.width, event->configure.height - ); - } - return FALSE; -} - -gboolean on_window_state_event(GtkWidget* widget, GdkEventWindowState* event, const gpointer self) { - auto* instance = reinterpret_cast(self); - instance->OnWindowStateEvent(event->new_window_state); - return TRUE; -} - -gboolean on_widget_deleted(GtkWidget* widget, GdkEvent* event, const gpointer self) { - auto* instance = reinterpret_cast(self); - return instance->InvokeClose(); -} - -void on_widget_destroyed(GtkWidget* widget, const gpointer self) { - auto* instance = reinterpret_cast(self); - instance->InvokeClosed(); -} - -gboolean on_focus_in_event(GtkWidget* widget, GdkEvent* event, const gpointer self) { - auto* instance = reinterpret_cast(self); - instance->InvokeFocusIn(); - return FALSE; -} - -gboolean on_focus_out_event(GtkWidget* widget, GdkEvent* event, const gpointer self) { - auto* instance = reinterpret_cast(self); - instance->InvokeFocusOut(); - return FALSE; -} - -gboolean on_webview_context_menu( - WebKitWebView* web_view, - GtkWidget* default_menu, - WebKitHitTestResult* hit_test_result, - gboolean triggered_with_keyboard, - const gpointer self - ) { - auto* instance = reinterpret_cast(self); - bool contextMenuEnabled = false; - instance->GetContextMenuEnabled(&contextMenuEnabled); - return !contextMenuEnabled; -} - -gboolean on_permission_request(WebKitWebView* web_view, WebKitPermissionRequest* request, gpointer user_data) { - auto* instance = reinterpret_cast(user_data); - bool grant = false; - instance->GetGrantBrowserPermissions(&grant); - if (grant) - webkit_permission_request_allow(request); - else - webkit_permission_request_deny(request); - return TRUE; -} - -void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data) { - if (!linux_webview_diagnostics_enabled()) - return; - - const char* uri = webkit_web_view_get_uri(web_view); - g_message( - "[InfiniFrame/Linux] WebKit load-changed: event=%s uri=%s", - webkit_load_event_to_string(load_event), - uri ? uri : "" - ); -} - -gboolean on_webview_load_failed( - WebKitWebView* web_view, - WebKitLoadEvent load_event, - gchar* failing_uri, - GError* error, - gpointer user_data - ) { - if (!linux_webview_diagnostics_enabled()) - return FALSE; - - g_warning( - "[InfiniFrame/Linux] WebKit load-failed: event=%s uri=%s error=%s", - webkit_load_event_to_string(load_event), - failing_uri ? failing_uri : "", - error ? error->message : "" - ); - return FALSE; -} - -void on_webview_process_terminated( - WebKitWebView* web_view, - WebKitWebProcessTerminationReason reason, - gpointer user_data - ) { - g_warning( - "[InfiniFrame/Linux] WebKit web process terminated: reason=%s", - webkit_termination_reason_to_string(reason) - ); -} - -void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data) { - if (!linux_webview_diagnostics_enabled()) - return; - - g_message( - "[InfiniFrame/Linux] WebView size-allocate: %dx%d", - allocation ? allocation->width : -1, - allocation ? allocation->height : -1 - ); -} - #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowSignals.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowSignals.Gtk.cpp new file mode 100644 index 000000000..bb4d6287c --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowSignals.Gtk.cpp @@ -0,0 +1,184 @@ +#ifdef __linux__ + +#include + +#include "Window.Gtk.Internal.h" + +namespace { + bool linux_webview_diagnostics_enabled() { + const char* value = g_getenv("INFINIFRAME_LINUX_WEBVIEW_DIAGNOSTICS"); + return value != nullptr && value[0] != '\0' && g_strcmp0(value, "0") != 0; + } + + const char* webkit_load_event_to_string(WebKitLoadEvent event) { + switch (event) { + case WEBKIT_LOAD_STARTED: + return "started"; + case WEBKIT_LOAD_REDIRECTED: + return "redirected"; + case WEBKIT_LOAD_COMMITTED: + return "committed"; + case WEBKIT_LOAD_FINISHED: + return "finished"; + default: + return "unknown"; + } + } + + const char* webkit_termination_reason_to_string(WebKitWebProcessTerminationReason reason) { + switch (reason) { + case WEBKIT_WEB_PROCESS_CRASHED: + return "crashed"; + case WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: + return "exceeded-memory-limit"; + case WEBKIT_WEB_PROCESS_TERMINATED_BY_API: + return "terminated-by-api"; + default: + return "unknown"; + } + } +} + +void InfiniFrameWindow::OnConfigureEvent(int x, int y, int width, int height) { + if (m_impl->_lastLeft != x || m_impl->_lastTop != y) { + InvokeMove(x, y); + m_impl->_lastLeft = x; + m_impl->_lastTop = y; + } + + if (m_impl->_lastHeight != height || m_impl->_lastWidth != width) { + InvokeResize(width, height); + m_impl->_lastWidth = width; + m_impl->_lastHeight = height; + } +} + +void InfiniFrameWindow::OnWindowStateEvent(GdkWindowState newState) { + if (newState & GDK_WINDOW_STATE_MAXIMIZED) { + InvokeMaximized(); + } + else if ((newState & GDK_WINDOW_STATE_ICONIFIED) || !gtk_widget_get_mapped(m_impl->_window)) { + InvokeMinimized(); + } + else if (!(newState & GDK_WINDOW_STATE_MAXIMIZED) && !(newState & GDK_WINDOW_STATE_ICONIFIED)) { + InvokeRestored(); + } +} + +gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, const gpointer self) { + if (event->type == GDK_CONFIGURE) { + auto* instance = reinterpret_cast(self); + instance->OnConfigureEvent( + event->configure.x, event->configure.y, + event->configure.width, event->configure.height + ); + } + return FALSE; +} + +gboolean on_window_state_event(GtkWidget* widget, GdkEventWindowState* event, const gpointer self) { + auto* instance = reinterpret_cast(self); + instance->OnWindowStateEvent(event->new_window_state); + return TRUE; +} + +gboolean on_widget_deleted(GtkWidget* widget, GdkEvent* event, const gpointer self) { + auto* instance = reinterpret_cast(self); + return instance->InvokeClose(); +} + +void on_widget_destroyed(GtkWidget* widget, const gpointer self) { + auto* instance = reinterpret_cast(self); + instance->InvokeClosed(); +} + +gboolean on_focus_in_event(GtkWidget* widget, GdkEvent* event, const gpointer self) { + auto* instance = reinterpret_cast(self); + instance->InvokeFocusIn(); + return FALSE; +} + +gboolean on_focus_out_event(GtkWidget* widget, GdkEvent* event, const gpointer self) { + auto* instance = reinterpret_cast(self); + instance->InvokeFocusOut(); + return FALSE; +} + +gboolean on_webview_context_menu( + WebKitWebView* web_view, + GtkWidget* default_menu, + WebKitHitTestResult* hit_test_result, + gboolean triggered_with_keyboard, + const gpointer self + ) { + auto* instance = reinterpret_cast(self); + bool contextMenuEnabled = false; + instance->GetContextMenuEnabled(&contextMenuEnabled); + return !contextMenuEnabled; +} + +gboolean on_permission_request(WebKitWebView* web_view, WebKitPermissionRequest* request, gpointer user_data) { + auto* instance = reinterpret_cast(user_data); + bool grant = false; + instance->GetGrantBrowserPermissions(&grant); + if (grant) + webkit_permission_request_allow(request); + else + webkit_permission_request_deny(request); + return TRUE; +} + +void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data) { + if (!linux_webview_diagnostics_enabled()) + return; + + const char* uri = webkit_web_view_get_uri(web_view); + g_message( + "[InfiniFrame/Linux] WebKit load-changed: event=%s uri=%s", + webkit_load_event_to_string(load_event), + uri ? uri : "" + ); +} + +gboolean on_webview_load_failed( + WebKitWebView* web_view, + WebKitLoadEvent load_event, + gchar* failing_uri, + GError* error, + gpointer user_data + ) { + if (!linux_webview_diagnostics_enabled()) + return FALSE; + + g_warning( + "[InfiniFrame/Linux] WebKit load-failed: event=%s uri=%s error=%s", + webkit_load_event_to_string(load_event), + failing_uri ? failing_uri : "", + error ? error->message : "" + ); + return FALSE; +} + +void on_webview_process_terminated( + WebKitWebView* web_view, + WebKitWebProcessTerminationReason reason, + gpointer user_data + ) { + g_warning( + "[InfiniFrame/Linux] WebKit web process terminated: reason=%s", + webkit_termination_reason_to_string(reason) + ); +} + +void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data) { + if (!linux_webview_diagnostics_enabled()) + return; + + g_message( + "[InfiniFrame/Linux] WebView size-allocate: %dx%d", + allocation ? allocation->width : -1, + allocation ? allocation->height : -1 + ); +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp new file mode 100644 index 000000000..3680da596 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp @@ -0,0 +1,47 @@ +#include + +#include "Window.Win32.Context.h" + +void InfiniFrameWindow::Invoke(ACTION callback) { + if (!callback) + return; + + if (m_impl->_hWnd == nullptr || !IsWindow(m_impl->_hWnd)) + return; + + auto* waitInfo = new InvokeWaitInfo(); + if (!PostMessage( + m_impl->_hWnd, WM_USER_INVOKE, reinterpret_cast(callback), reinterpret_cast(waitInfo) + )) { + delete waitInfo; + return; + } + + std::unique_lock uLock(waitInfo->mutex); + const bool completed = waitInfo->completionNotifier.wait_for( + uLock, + std::chrono::seconds(15), + [&] { + return waitInfo->isCompleted; + } + ); + + if (!completed) { + bool deleteWaitInfo = false; + if (waitInfo->isCompleted) + deleteWaitInfo = true; + else + waitInfo->isAbandoned = true; + + uLock.unlock(); + + if (deleteWaitInfo) + delete waitInfo; + + OutputDebugStringW(L"InfiniFrameWindow::Invoke timed out waiting for UI thread callback.\n"); + return; + } + + uLock.unlock(); + delete waitInfo; +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp new file mode 100644 index 000000000..10381ba3c --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp @@ -0,0 +1,826 @@ +#include +#include +#include + +#include "Window.Win32.Context.h" +#include "Embedded/Embedded.h" + +using namespace Microsoft::WRL; + +void InfiniFrameWindow::CloseWebView() { + m_impl->_isClosingOrClosed.store(true, std::memory_order_release); + const bool deferEnvironmentRelease = + m_impl->_isWebView2Initializing && m_impl->_webviewController == nullptr; + TraceTeardown( + L"CloseWebView begin instance=%p hwnd=%p controller=%p webview=%p env=%p", + this, + m_impl->_hWnd, + m_impl->_webviewController.get(), + m_impl->_webviewWindow.get(), + m_impl->_webviewEnvironment.get() + ); + + if (m_impl->_webviewController != nullptr) { + m_impl->_webviewController->Close(); + m_impl->_webviewController = nullptr; + } + + m_impl->_webviewWindow = nullptr; + + m_impl->_hasWebMessageReceivedToken = false; + m_impl->_hasWebResourceRequestedToken = false; + m_impl->_hasPermissionRequestedToken = false; + m_impl->_webMessageReceivedToken = {}; + m_impl->_webResourceRequestedTokenForCustomScheme = {}; + m_impl->_permissionRequestedToken = {}; + + if (m_impl->_webviewEnvironment != nullptr && !deferEnvironmentRelease) { + m_impl->_webviewEnvironment = nullptr; + } + + m_impl->_isInitialized = false; + if (!deferEnvironmentRelease) + m_impl->_isWebView2Initializing = false; + + if (deferEnvironmentRelease) { + TraceTeardown( + L"CloseWebView deferring environment release instance=%p env=%p", + this, + m_impl->_webviewEnvironment.get() + ); + } + + TraceTeardown(L"CloseWebView end instance=%p", this); +} + +std::string InfiniFrameWindow::ToUTF8String(const AutoString source) const { + return WideToUtf8(source); +} + +std::wstring InfiniFrameWindow::ToUTF16String(const AutoString source) const { + return Utf8ToWide(source); +} + +bool InfiniFrameWindow::EnsureWebViewIsInstalled() { + LPWSTR versionInfo = nullptr; + HRESULT ensureInstalledResult = GetAvailableCoreWebView2BrowserVersionString(nullptr, &versionInfo); + if (versionInfo != nullptr) + CoTaskMemFree(versionInfo); + + if (ensureInstalledResult != S_OK) + return InstallWebView2(); + + return true; +} + +bool InfiniFrameWindow::InstallWebView2() { + auto srcURL = L"https://go.microsoft.com/fwlink/p/?LinkId=2124703"; + auto destFile = L"MicrosoftEdgeWebview2Setup.exe"; + + if (S_OK == URLDownloadToFile(nullptr, srcURL, destFile, 0, nullptr)) { + std::wstring command = L"MicrosoftEdgeWebview2Setup.exe"; + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + bool success = CreateProcess( + nullptr, + command.data(), + nullptr, + nullptr, + FALSE, + 0, + nullptr, + nullptr, + &si, + &pi + ); + + if (success) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + return success; + } + + return false; +} + +void InfiniFrameWindow::RefitContent() { + if (m_impl->_webviewController) { + RECT bounds; + GetClientRect(m_impl->_hWnd, &bounds); + m_impl->_webviewController->put_Bounds(bounds); + } +} + +void InfiniFrameWindow::FocusWebView2() { + if (m_impl->_webviewController) { + m_impl->_webviewController->MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC); + } +} + +void InfiniFrameWindow::NotifyWebView2WindowMove() { + if (m_impl->_webviewController) { + m_impl->_webviewController->NotifyParentWindowPositionChanged(); + } +} + +void InfiniFrameWindow::ClearBrowserAutoFill() { + if (!m_impl->_webviewWindow) + return; + + auto webview15 = m_impl->_webviewWindow.try_query(); + if (webview15) { + wil::com_ptr profile; + webview15->get_Profile(&profile); + auto profile2 = profile.try_query(); + + if (profile2) { + COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds = + (COREWEBVIEW2_BROWSING_DATA_KINDS) + ( + COREWEBVIEW2_BROWSING_DATA_KINDS_GENERAL_AUTOFILL | + COREWEBVIEW2_BROWSING_DATA_KINDS_PASSWORD_AUTOSAVE + ); + + profile2->ClearBrowsingData( + dataKinds, + Callback( + [this]( + HRESULT + ) + -> HRESULT { + return S_OK; + } + ) + .Get() + ); + } + } +} + +void InfiniFrameWindow::SetWebView2RuntimePath(const AutoString pathToWebView2) { + if (pathToWebView2 == nullptr) + return; + + std::wstring widePath = Utf8ToWide(pathToWebView2); + std::lock_guard lock(webview2RuntimePathMutex); + wcsncpy_s(_webview2RuntimePath, widePath.c_str(), _countof(_webview2RuntimePath)); +} + +void InfiniFrameWindow::Show(const bool isAlreadyShown) { + if (!isAlreadyShown) + ShowWindow(m_impl->_hWnd, SW_SHOWDEFAULT); + + UpdateWindow(m_impl->_hWnd); + + if (!m_impl->_webviewController) { + bool hasConfiguredRuntimePath = false; + { + std::lock_guard lock(webview2RuntimePathMutex); + hasConfiguredRuntimePath = wcsnlen(_webview2RuntimePath, _countof(_webview2RuntimePath)) > 0; + } + if (hasConfiguredRuntimePath || EnsureWebViewIsInstalled()) + AttachWebView(); + else + exit(0); + } +} + +void InfiniFrameWindow::AttachWebView() { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return; + + if (m_impl->_isWebView2Initializing || m_impl->_isInitialized) + return; + m_impl->_isWebView2Initializing = true; + + std::wstring configuredRuntimePath; + { + std::lock_guard lock(webview2RuntimePathMutex); + configuredRuntimePath = _webview2RuntimePath; + } + PCWSTR runtimePath = configuredRuntimePath.empty() ? nullptr : configuredRuntimePath.c_str(); + + std::wstring startupString; + if (!m_impl->_userAgent.empty()) + startupString += L"--user-agent=\"" + m_impl->_userAgent + L"\" "; + if (m_impl->_mediaAutoplayEnabled) + startupString += L"--autoplay-policy=no-user-gesture-required "; + if (m_impl->_fileSystemAccessEnabled) + startupString += L"--allow-file-access-from-files "; + if (!m_impl->_webSecurityEnabled) + startupString += L"--disable-web-security "; + if (m_impl->_javascriptClipboardAccessEnabled) + startupString += L"--enable-javascript-clipboard-access "; + if (m_impl->_mediaStreamEnabled) + startupString += L"--enable-usermedia-screen-capturing "; + if (!m_impl->_smoothScrollingEnabled) + startupString += L"--disable-smooth-scrolling "; + if (m_impl->_ignoreCertificateErrorsEnabled) + startupString += L"--ignore-certificate-errors "; + if (!m_impl->_browserControlInitParameters.empty()) + startupString += m_impl->_browserControlInitParameters; //e.g.--hide-scrollbars + + auto options = Microsoft::WRL::Make(); + if (startupString.length() > 0) + options->put_AdditionalBrowserArguments(startupString.c_str()); + + bool requiresAppSchemeRegistration = std::any_of( + m_impl->_customSchemeNames.begin(), + m_impl->_customSchemeNames.end(), + [](const std::wstring& schemeName) { + return _wcsicmp(schemeName.c_str(), L"app") == 0; + } + ); + bool appSchemeRegistrationSupported = false; + + // Register custom schemes with WebView2 so top-level navigations like app://... are allowed. + if (!m_impl->_customSchemeNames.empty()) { + wil::com_ptr options4; + if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&options4))) && options4) { + appSchemeRegistrationSupported = true; + std::vector> registrations; + registrations.reserve(m_impl->_customSchemeNames.size()); + + for (const auto& schemeName : m_impl->_customSchemeNames) { + auto registration = Microsoft::WRL::Make(schemeName.c_str()); + if (!registration) + continue; + + // Only the embedded-assets scheme uses app://localhost/... and should be + // treated as secure with an authority component. + if (_wcsicmp(schemeName.c_str(), L"app") == 0) { + registration->put_HasAuthorityComponent(TRUE); + registration->put_TreatAsSecure(TRUE); + } + registrations.emplace_back(registration); + } + + if (!registrations.empty()) { + std::vector rawRegistrations; + rawRegistrations.reserve(registrations.size()); + for (auto& registration : registrations) + rawRegistrations.emplace_back(registration.get()); + + options4->SetCustomSchemeRegistrations( + static_cast(rawRegistrations.size()), + rawRegistrations.data() + ); + } + } + } + + if (requiresAppSchemeRegistration && !appSchemeRegistrationSupported) { + MessageBox( + m_impl->_hWnd, + L"This app requires WebView2 custom scheme registration for app://localhost/. Please update WebView2 Runtime to a version that supports ICoreWebView2EnvironmentOptions4.", + L"WebView2 Runtime Too Old", + MB_OK | MB_ICONERROR + ); + m_impl->_isWebView2Initializing = false; + return; + } + + PCWSTR userDataPath = nullptr; + if (!m_impl->_temporaryFilesPath.empty()) { + if (EnsureDirectoryWritable(m_impl->_temporaryFilesPath)) + userDataPath = m_impl->_temporaryFilesPath.c_str(); + else + TraceTeardown( + L"AttachWebView: temporary user-data path is not writable. Falling back to default path. path=%ls", + m_impl->_temporaryFilesPath.c_str() + ); + } + + HRESULT envResult = CreateCoreWebView2EnvironmentWithOptions( + runtimePath, + userDataPath, + options.Get(), + Callback< + ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>( + [this]( + const HRESULT result, + ICoreWebView2Environment* env + ) -> HRESULT { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { + m_impl->_isWebView2Initializing = false; + m_impl->_webviewEnvironment = nullptr; + TraceTeardown(L"CreateEnvironment callback while closing; ignoring"); + return S_OK; + } + if (result != S_OK) { + m_impl->_isWebView2Initializing = false; + TraceTeardown(L"CreateEnvironment callback failed hr=0x%08X", static_cast(result)); + return result; + } + if (env == nullptr) { + m_impl->_isWebView2Initializing = false; + return E_POINTER; + } + HRESULT envResult = env->QueryInterface( + &m_impl->_webviewEnvironment + ); + if (envResult != S_OK) { + m_impl->_isWebView2Initializing = false; + return envResult; + } + + const HRESULT createControllerHr = env->CreateCoreWebView2Controller( + m_impl->_hWnd, + Callback< + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>( + [this]( + const HRESULT result, + ICoreWebView2Controller* controller + ) -> + HRESULT { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { + if (controller != nullptr) + controller->Close(); + m_impl->_webviewController = nullptr; + m_impl->_webviewWindow = nullptr; + m_impl->_webviewEnvironment = nullptr; + m_impl->_isWebView2Initializing = false; + TraceTeardown(L"CreateController callback while closing; ignoring"); + return S_OK; + } + if (result != S_OK) { + m_impl->_isWebView2Initializing = false; + TraceTeardown(L"CreateController callback failed hr=0x%08X", static_cast(result)); + return result; + } + if (controller == nullptr) { + m_impl->_isWebView2Initializing = false; + return E_POINTER; + } + + HRESULT envResult = controller-> + QueryInterface( + &m_impl-> + _webviewController + ); + if (envResult != S_OK) { + m_impl->_isWebView2Initializing = false; + return envResult; + } + m_impl->_webviewController->get_CoreWebView2(&m_impl->_webviewWindow); + if (!m_impl->_webviewWindow) { + m_impl->_isWebView2Initializing = false; + return E_FAIL; + } + + const auto js_wide = Embedded::InfiniFrameJsUtf16(); + OutputDebugStringW(std::format(L"[InfiniFrame] Bridge script length: {} chars\n", js_wide.size()).c_str()); + + // AddScriptToExecuteOnDocumentCreated is async: the script is not + // registered in the browser process until the completion callback fires. + // We must not navigate until then, otherwise fast local navigations + // (e.g., app://localhost/) reach ContentLoading before the bridge script + // exists, and Blazor's Boot.WebView.ts throws because + // window.external.receiveMessage is undefined. + // + // If script registration fails for any reason (e.g., empty resource), + // we fall through and navigate anyway so the page still loads. + struct NavigateOnce { + InfiniFrameWindow* self; + bool fired = false; + void navigate() { + if (fired) return; + fired = true; + if (!self->m_impl->_startUrl.empty()) + self->m_impl->_webviewWindow->Navigate(self->m_impl->_startUrl.c_str()); + else if (!self->m_impl->_startString.empty()) + self->m_impl->_webviewWindow->NavigateToString(self->m_impl->_startString.c_str()); + else { + MessageBox(nullptr, + L"Neither StartUrl nor StartString was specified", + L"Native Initialization Failed", MB_OK); + exit(0); + } + } + }; + auto nav = std::make_shared(NavigateOnce{this}); + + wil::com_ptr + settings; + HRESULT settingsResult = m_impl-> + _webviewWindow->get_Settings( + &settings + ); + if (FAILED(settingsResult) || ! + settings) { + return FAILED(settingsResult) + ? settingsResult + : E_FAIL; + } + settings-> + put_AreHostObjectsAllowed( + TRUE + ); + settings->put_IsScriptEnabled( + TRUE + ); + settings-> + put_AreDefaultScriptDialogsEnabled( + TRUE + ); + settings->put_IsWebMessageEnabled( + TRUE + ); + + EventRegistrationToken + webMessageToken; + + m_impl->_webviewWindow-> + add_WebMessageReceived( + Callback< + ICoreWebView2WebMessageReceivedEventHandler>( + [this]( + ICoreWebView2*, + ICoreWebView2WebMessageReceivedEventArgs + * args + ) -> HRESULT { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return S_OK; + + wil::unique_cotaskmem_string + message; + wil::unique_cotaskmem_string + source; + args-> + TryGetWebMessageAsString( + &message + ); + args-> + get_Source( + &source + ); + if ( + (source.get() == nullptr + || source.get()[0] == L'\0') + && m_impl->_webviewWindow != nullptr + ) { + m_impl-> + _webviewWindow-> + get_Source( + &source + ); + } + m_impl-> + _webMessageReceivedCallback( + message. + get(), + source. + get() + ); + return S_OK; + } + ).Get(), + &webMessageToken + ); + m_impl->_webMessageReceivedToken = webMessageToken; + m_impl->_hasWebMessageReceivedToken = true; + + EventRegistrationToken + webResourceRequestedToken; + auto webview23 = m_impl->_webviewWindow.try_query(); + if (webview23) { + webview23->AddWebResourceRequestedFilterWithRequestSourceKinds( + L"*", + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL + ); + } + else { + m_impl->_webviewWindow-> + AddWebResourceRequestedFilter( + L"*", + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL + ); + } + m_impl->_webviewWindow-> + add_WebResourceRequested( + Callback< + ICoreWebView2WebResourceRequestedEventHandler>( + [this]( + ICoreWebView2*, + ICoreWebView2WebResourceRequestedEventArgs + * args + ) { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return S_OK; + + wil::com_ptr< + ICoreWebView2WebResourceRequest> + req; + if (FAILED( + args-> + get_Request( + &req + ) + ) + || ! + req) + return S_OK; + + wil::unique_cotaskmem_string + uri; + req->get_Uri(&uri); + std::wstring + uriString = uri + .get(); + wil::com_ptr + requestHeaders; + std::wstring requestOrigin; + if (SUCCEEDED(req->get_Headers(&requestHeaders)) && requestHeaders) { + wil::unique_cotaskmem_string originHeaderValue; + if (SUCCEEDED( + requestHeaders->GetHeader(L"Origin", &originHeaderValue) + ) + && originHeaderValue.get() != nullptr + && originHeaderValue.get()[0] != L'\0') { + requestOrigin = originHeaderValue.get(); + } + } + + if (uriString.find(L"/_framework/blazor.modules.json") != + std::wstring::npos) { + static constexpr BYTE emptyModuleArray[] = {'[', ']'}; + wil::com_ptr dataStream; + dataStream.attach( + SHCreateMemStream(emptyModuleArray, sizeof(emptyModuleArray)) + ); + if (!dataStream) + return S_OK; + + std::wstring responseHeaders = L"Content-Type: application/json"; + responseHeaders += + L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; + responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; + if (!requestOrigin.empty()) { + responseHeaders += L"\r\nAccess-Control-Allow-Origin: " + + requestOrigin; + responseHeaders += + L"\r\nAccess-Control-Allow-Credentials: true"; + responseHeaders += L"\r\nVary: Origin"; + } + else { + responseHeaders += L"\r\nAccess-Control-Allow-Origin: *"; + } + + wil::com_ptr response; + m_impl->_webviewEnvironment->CreateWebResourceResponse( + dataStream.get(), + 200, + L"OK", + responseHeaders.c_str(), + &response + ); + args->put_Response(response.get()); + return S_OK; + } + size_t colonPos = + uriString.find( + L':', 0 + ); + if (colonPos > 0) { + std::wstring + scheme = + uriString + .substr( + 0, + colonPos + ); + auto it = + std::find( + m_impl + -> + _customSchemeNames + .begin(), + m_impl + -> + _customSchemeNames + .end(), + scheme + ); + + if (it != + m_impl-> + _customSchemeNames + .end() && + m_impl-> + _customSchemeCallback + != + nullptr) { + int + numBytes; + AutoString + contentType + = nullptr; + wil::unique_cotaskmem + dotNetResponse( + m_impl + -> + _customSchemeCallback( + const_cast + + (uriString + .c_str()), + &numBytes, + &contentType + ) + ); + auto + freeContentType + = wil::scope_exit( + [& + contentType + ] { + CoTaskMemFree( + contentType + ); + } + ); + + if ( + dotNetResponse + != + nullptr + && + contentType + != + nullptr) { + std::wstring + contentTypeWS + = contentType; + + wil::com_ptr + + dataStream; + dataStream + .attach( + SHCreateMemStream( + reinterpret_cast + + (dotNetResponse + .get()), + numBytes + ) + ); + if (! + dataStream) + return + S_OK; + wil::com_ptr + + response; + std::wstring responseHeaders = L"Content-Type: " + + contentTypeWS; + responseHeaders += + L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; + responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; + if (!requestOrigin.empty()) { + responseHeaders += L"\r\nAccess-Control-Allow-Origin: " + + requestOrigin; + responseHeaders += + L"\r\nAccess-Control-Allow-Credentials: true"; + responseHeaders += L"\r\nVary: Origin"; + } + else { + responseHeaders += + L"\r\nAccess-Control-Allow-Origin: *"; + } + m_impl + -> + _webviewEnvironment + -> + CreateWebResourceResponse( + dataStream + .get(), + 200, + L"OK", + responseHeaders.c_str(), + &response + ); + args-> + put_Response( + response + .get() + ); + } + } + } + + return S_OK; + } + ).Get(), + &webResourceRequestedToken + ); + m_impl->_webResourceRequestedTokenForCustomScheme = webResourceRequestedToken; + m_impl->_hasWebResourceRequestedToken = true; + + EventRegistrationToken + permissionRequestedToken; + m_impl->_webviewWindow-> + add_PermissionRequested( + Callback< + ICoreWebView2PermissionRequestedEventHandler>( + [this]( + ICoreWebView2*, + ICoreWebView2PermissionRequestedEventArgs + * args + ) -> HRESULT { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return S_OK; + + if (m_impl-> + _grantBrowserPermissions) + args-> + put_State( + COREWEBVIEW2_PERMISSION_STATE_ALLOW + ); + return S_OK; + } + ) + .Get(), + &permissionRequestedToken + ); + m_impl->_permissionRequestedToken = permissionRequestedToken; + m_impl->_hasPermissionRequestedToken = true; + + if (m_impl->_contextMenuEnabled == + false) + SetContextMenuEnabled(false); + + if (m_impl->_zoomEnabled == false) + SetZoomEnabled(false); + + if (m_impl->_devToolsEnabled == + false) + SetDevToolsEnabled(false); + + if (m_impl->_transparentEnabled == + true) + SetTransparentEnabled(true); + + if (m_impl->_zoom != 100) + SetZoom(m_impl->_zoom); + + HRESULT addScriptHr = m_impl->_webviewWindow->AddScriptToExecuteOnDocumentCreated( + js_wide.c_str(), + Callback( + [nav, this](HRESULT errorCode, LPCWSTR id) -> HRESULT { + OutputDebugStringW(std::format(L"[InfiniFrame] AddScriptToExecuteOnDocumentCreated callback: hr=0x{:08X} id={}\n", (unsigned)errorCode, id ? id : L"(null)").c_str()); + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return S_OK; + nav->navigate(); + return S_OK; + } + ).Get() + ); + + // If AddScriptToExecuteOnDocumentCreated itself failed synchronously + // (e.g., empty script string on some WebView2 versions), navigate now + // so the page is not left blank. + if (FAILED(addScriptHr)) + nav->navigate(); + + RefitContent(); + + FocusWebView2(); + + // Re-apply if topmost was requested + if (m_impl->_topmost) + SetTopmost(true); + + m_impl->_isInitialized = true; + m_impl->_isWebView2Initializing = false; + return S_OK; + } + ).Get() + ); + if (FAILED(createControllerHr)) + m_impl->_isWebView2Initializing = false; + + return createControllerHr; + } + ).Get() + ); + + if (envResult != S_OK) { + m_impl->_isWebView2Initializing = false; + _com_error err(envResult); + LPCTSTR errMsg = err.ErrorMessage(); + MessageBox(m_impl->_hWnd, errMsg, L"Error instantiating webview", MB_OK); + } +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h new file mode 100644 index 000000000..859f5f316 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h @@ -0,0 +1,91 @@ +#pragma once + +#ifndef INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_CONTEXT_H +#define INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_CONTEXT_H + +#include +#include +#include +#include + +#include + +#include "Core/InfiniFrameWindow.h" +#include "Window.Win32.Internal.h" + +inline constexpr UINT WM_USER_INVOKE = WM_USER + 0x0002; + +extern std::atomic _hInstance; +extern thread_local HWND messageLoopRootWindowHandle; +extern wchar_t _webview2RuntimePath[MAX_PATH]; +extern std::mutex webview2RuntimePathMutex; +extern const wchar_t* CLASS_NAME; + +struct InvokeWaitInfo { + std::mutex mutex; + std::condition_variable completionNotifier; + bool isCompleted = false; + bool isAbandoned = false; +}; + +bool IsTeardownTraceEnabled(); +void TraceTeardown(const wchar_t* format, ...); +std::wstring Utf8ToWide(AutoString source); +std::string WideToUtf8(AutoString source); +bool EnsureDirectoryWritable(const std::wstring& directoryPath); +InfiniFrameWindow* LookupWindowInstance(HWND hwnd); +HWND ResolveParentWindowHandle(InfiniFrameWindow* parent); +HBRUSH GetDarkBrush(); +HBRUSH GetLightBrush(); + +template +inline void ApplyPendingOwnerWindow(TImpl* impl, const wchar_t* phase) { + if (impl == nullptr) + return; + if (impl->_ownerAssigned) + return; + + if (impl->_pendingOwnerHwnd == nullptr || impl->_hWnd == nullptr) + return; + + if (impl->_pendingOwnerHwnd == impl->_hWnd) + return; + + if (!IsWindow(impl->_pendingOwnerHwnd) || !IsWindow(impl->_hWnd)) + return; + + SetLastError(0); + const LONG_PTR previousOwner = SetWindowLongPtr( + impl->_hWnd, + GWLP_HWNDPARENT, + reinterpret_cast(impl->_pendingOwnerHwnd) + ); + const DWORD lastError = GetLastError(); + + if (previousOwner == 0 && lastError != 0) { + TraceTeardown( + L"ApplyPendingOwnerWindow failed phase=%ls child=%p owner=%p err=%lu", + phase, + impl->_hWnd, + impl->_pendingOwnerHwnd, + lastError + ); + return; + } + + impl->_ownerAssigned = true; + + const DWORD childThreadId = GetWindowThreadProcessId(impl->_hWnd, nullptr); + const DWORD ownerThreadId = GetWindowThreadProcessId(impl->_pendingOwnerHwnd, nullptr); + TraceTeardown( + L"ApplyPendingOwnerWindow success phase=%ls child=%p owner=%p childTid=%lu ownerTid=%lu prev=%p", + phase, + impl->_hWnd, + impl->_pendingOwnerHwnd, + childThreadId, + ownerThreadId, + reinterpret_cast(previousOwner) + ); +} + +#endif // INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_CONTEXT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp index 453360a25..863cc5435 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp @@ -1,15 +1,12 @@ #include -#include #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -25,6 +22,7 @@ #include "DarkMode.h" #include "ToastHandler.h" #include "Utils/Common.h" +#include "Window.Win32.Context.h" #include "Window.Win32.Internal.h" #include "Embedded/Embedded.h" @@ -32,732 +30,157 @@ #pragma comment(lib, "Shcore.lib") #pragma comment(lib, "Urlmon.lib") -#define WM_USER_INVOKE (WM_USER + 0x0002) - using namespace WinToastLib; using namespace Microsoft::WRL; LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -auto CLASS_NAME = L"InfiniFrame"; +const wchar_t* CLASS_NAME = L"InfiniFrame"; std::atomic _hInstance{nullptr}; thread_local HWND messageLoopRootWindowHandle = nullptr; wchar_t _webview2RuntimePath[MAX_PATH]; std::mutex webview2RuntimePathMutex; -namespace { - static_assert(sizeof(wchar_t) == sizeof(char16_t)); - - bool IsTeardownTraceEnabled() { - static const bool enabled = [] { - wchar_t value[32] = {}; - const DWORD len = GetEnvironmentVariableW(L"INFINIFRAME_TRACE_TEARDOWN", value, _countof(value)); - if (len == 0 || len >= _countof(value)) - return false; - - return _wcsicmp(value, L"1") == 0 - || _wcsicmp(value, L"true") == 0 - || _wcsicmp(value, L"yes") == 0 - || _wcsicmp(value, L"on") == 0; - }(); - - return enabled; - } - - void TraceTeardown(const wchar_t* format, ...) { - if (!IsTeardownTraceEnabled()) - return; - - wchar_t message[1024] = {}; - va_list args; - va_start(args, format); - _vsnwprintf_s(message, _countof(message), _TRUNCATE, format, args); - va_end(args); - - const std::wstring line = std::format( - L"[InfiniFrame][teardown][tid={}] {}\n", - GetCurrentThreadId(), - message - ); - OutputDebugStringW(line.c_str()); - std::fwprintf(stderr, L"%ls", line.c_str()); - std::fflush(stderr); - } - - std::wstring Utf8ToWide(const AutoString source) { - if (source == nullptr) - return {}; - - const auto* utf8 = reinterpret_cast(source); - const size_t utf8Length = strlen(utf8); - if (utf8Length == 0) - return {}; - - if (const auto validation = simdutf::validate_utf8_with_errors(utf8, utf8Length); validation.is_err()) - return {}; - - std::u16string utf16(simdutf::utf16_length_from_utf8(utf8, utf8Length), u'\0'); - const size_t written = simdutf::convert_valid_utf8_to_utf16( - utf8, - utf8Length, - reinterpret_cast(utf16.data()) - ); - utf16.resize(written); - - return { - reinterpret_cast(utf16.data()), - utf16.size() - }; - } - - std::string WideToUtf8(const AutoString source) { - if (source == nullptr) - return {}; - - const size_t utf16Length = wcslen(source); - if (utf16Length == 0) - return {}; - - const auto* utf16 = reinterpret_cast(source); - if (const auto validation = simdutf::validate_utf16_with_errors(utf16, utf16Length); validation.is_err()) - return {}; +static_assert(sizeof(wchar_t) == sizeof(char16_t)); - std::string utf8(simdutf::utf8_length_from_utf16(utf16, utf16Length), '\0'); - const size_t written = simdutf::convert_valid_utf16_to_utf8( - utf16, - utf16Length, - utf8.data() - ); - utf8.resize(written); - - return utf8; - } - - bool EnsureDirectoryWritable(const std::wstring& directoryPath) { - if (directoryPath.empty()) - return false; - - std::error_code createError; - std::filesystem::create_directories(directoryPath, createError); - if (createError) - return false; - - const std::wstring probePath = std::format( - L"{}\\{}.tmp", - directoryPath, - std::format(L".infiniframe-wv2-write-check-{}-{}-{}", GetCurrentProcessId(), GetCurrentThreadId(), GetTickCount64()) - ); - - HANDLE probeHandle = CreateFileW( - probePath.c_str(), - GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, - CREATE_ALWAYS, - FILE_ATTRIBUTE_TEMPORARY, - nullptr - ); - - if (probeHandle == INVALID_HANDLE_VALUE) +bool IsTeardownTraceEnabled() { + static const bool enabled = [] { + wchar_t value[32] = {}; + const DWORD len = GetEnvironmentVariableW(L"INFINIFRAME_TRACE_TEARDOWN", value, _countof(value)); + if (len == 0 || len >= _countof(value)) return false; - CloseHandle(probeHandle); - DeleteFileW(probePath.c_str()); - return true; - } - - InfiniFrameWindow* LookupWindowInstance(const HWND hwnd) { - return reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - } - - HWND ResolveParentWindowHandle(InfiniFrameWindow* parent) { - if (parent == nullptr) - return nullptr; - - HWND parentHwnd = parent->getHwnd(); - if (parentHwnd == nullptr || !IsWindow(parentHwnd)) - return nullptr; - - return parentHwnd; - } - - template - void ApplyPendingOwnerWindow(TImpl* impl, const wchar_t* phase) { - if (impl == nullptr) - return; - if (impl->_ownerAssigned) - return; + return _wcsicmp(value, L"1") == 0 + || _wcsicmp(value, L"true") == 0 + || _wcsicmp(value, L"yes") == 0 + || _wcsicmp(value, L"on") == 0; + }(); - if (impl->_pendingOwnerHwnd == nullptr || impl->_hWnd == nullptr) - return; - - if (impl->_pendingOwnerHwnd == impl->_hWnd) - return; - - if (!IsWindow(impl->_pendingOwnerHwnd) || !IsWindow(impl->_hWnd)) - return; - - SetLastError(0); - const LONG_PTR previousOwner = SetWindowLongPtr( - impl->_hWnd, - GWLP_HWNDPARENT, - reinterpret_cast(impl->_pendingOwnerHwnd) - ); - const DWORD lastError = GetLastError(); - - if (previousOwner == 0 && lastError != 0) { - TraceTeardown( - L"ApplyPendingOwnerWindow failed phase=%ls child=%p owner=%p err=%lu", - phase, - impl->_hWnd, - impl->_pendingOwnerHwnd, - lastError - ); - return; - } - - impl->_ownerAssigned = true; - - const DWORD childThreadId = GetWindowThreadProcessId(impl->_hWnd, nullptr); - const DWORD ownerThreadId = GetWindowThreadProcessId(impl->_pendingOwnerHwnd, nullptr); - TraceTeardown( - L"ApplyPendingOwnerWindow success phase=%ls child=%p owner=%p childTid=%lu ownerTid=%lu prev=%p", - phase, - impl->_hWnd, - impl->_pendingOwnerHwnd, - childThreadId, - ownerThreadId, - reinterpret_cast(previousOwner) - ); - } + return enabled; } +void TraceTeardown(const wchar_t* format, ...) { + if (!IsTeardownTraceEnabled()) + return; -struct InvokeWaitInfo { - std::mutex mutex; - std::condition_variable completionNotifier; - bool isCompleted = false; - bool isAbandoned = false; -}; - -struct ShowMessageParams { - std::wstring title; - std::wstring body; - UINT type = 0; -}; - -namespace detail { - class BrushManager { - public: - static BrushManager& instance() noexcept { - static BrushManager inst; - return inst; - } + wchar_t message[1024] = {}; + va_list args; + va_start(args, format); + _vsnwprintf_s(message, _countof(message), _TRUNCATE, format, args); + va_end(args); - HBRUSH dark() const noexcept { - return static_cast(m_darkBrush.get()); - } + const std::wstring line = std::format( + L"[InfiniFrame][teardown][tid={}] {}\n", + GetCurrentThreadId(), + message + ); + OutputDebugStringW(line.c_str()); + std::fwprintf(stderr, L"%ls", line.c_str()); + std::fflush(stderr); +} - HBRUSH light() const noexcept { - return static_cast(m_lightBrush.get()); - } +std::wstring Utf8ToWide(const AutoString source) { + if (source == nullptr) + return {}; - private: - BrushManager() noexcept { - m_darkBrush.reset(CreateSolidBrush(RGB(0, 0, 0))); - m_lightBrush.reset(CreateSolidBrush(RGB(255, 255, 255))); - } + const auto* utf8 = reinterpret_cast(source); + const size_t utf8Length = strlen(utf8); + if (utf8Length == 0) + return {}; - ~BrushManager() noexcept = default; + if (const auto validation = simdutf::validate_utf8_with_errors(utf8, utf8Length); validation.is_err()) + return {}; - struct HBRUSHDeleter { - void operator()(void* h) const noexcept { - if (h) - DeleteObject(static_cast(h)); - } - }; + std::u16string utf16(simdutf::utf16_length_from_utf8(utf8, utf8Length), u'\0'); + const size_t written = simdutf::convert_valid_utf8_to_utf16( + utf8, + utf8Length, + reinterpret_cast(utf16.data()) + ); + utf16.resize(written); - std::unique_ptr m_darkBrush; - std::unique_ptr m_lightBrush; + return { + reinterpret_cast(utf16.data()), + utf16.size() }; -} // namespace detail - -void InfiniFrameWindow::Register(const HINSTANCE hInstance) { - InitDarkModeSupport(); - - _hInstance.store(hInstance, std::memory_order_release); - - // Register the window class - WNDCLASSEX wcx; - wcx.cbSize = sizeof(WNDCLASSEX); - wcx.style = CS_HREDRAW | CS_VREDRAW; - wcx.lpfnWndProc = WindowProc; - wcx.cbClsExtra = 0; - wcx.cbWndExtra = 0; - wcx.hInstance = hInstance; - wcx.hIcon = LoadIcon(hInstance, IDI_APPLICATION); - wcx.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcx.hbrBackground = IsDarkModeEnabled() - ? detail::BrushManager::instance().dark() - : detail::BrushManager::instance().light(); - wcx.lpszMenuName = nullptr; - wcx.lpszClassName = CLASS_NAME; - wcx.hIconSm = LoadIcon(hInstance, IDI_APPLICATION); - - RegisterClassEx(&wcx); - - SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); } -InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { - m_impl = std::make_unique(); - if (initParams->Size != sizeof(InfiniFrameInitParams)) { - auto msg = std::format( - L"Initial parameters passed are {} bytes, but expected {} bytes.", - initParams->Size, sizeof(InfiniFrameInitParams) - ); - MessageBox(nullptr, msg.c_str(), L"Native Initialization Failed", MB_OK); - exit(0); - } - - if (initParams->Title != nullptr) { - m_impl->_windowTitle = ToUTF16String(initParams->Title); - if (initParams->NotificationsEnabled) { - WinToast::instance()->setAppName(m_impl->_windowTitle.c_str()); - if (m_impl->_notificationRegistrationId.empty()) - WinToast::instance()->setAppUserModelId(m_impl->_windowTitle.c_str()); - } - } - - if (initParams->StartUrl != nullptr) - m_impl->_startUrl = ToUTF16String(initParams->StartUrl); - - if (initParams->StartString != nullptr) - m_impl->_startString = ToUTF16String(initParams->StartString); - - if (initParams->TemporaryFilesPath != nullptr) - m_impl->_temporaryFilesPath = ToUTF16String(initParams->TemporaryFilesPath); - - if (initParams->UserAgent != nullptr) - m_impl->_userAgent = ToUTF16String(initParams->UserAgent); - - if (initParams->BrowserControlInitParameters != nullptr) - m_impl->_browserControlInitParameters = ToUTF16String(initParams->BrowserControlInitParameters); - - if (initParams->NotificationRegistrationId != nullptr) - m_impl->_notificationRegistrationId = ToUTF16String(initParams->NotificationRegistrationId); - - - m_impl->_transparentEnabled = initParams->Transparent; - m_impl->_contextMenuEnabled = initParams->ContextMenuEnabled; - m_impl->_zoomEnabled = initParams->ZoomEnabled; - m_impl->_devToolsEnabled = initParams->DevToolsEnabled; - m_impl->_grantBrowserPermissions = initParams->GrantBrowserPermissions; - m_impl->_mediaAutoplayEnabled = initParams->MediaAutoplayEnabled; - m_impl->_fileSystemAccessEnabled = initParams->FileSystemAccessEnabled; - m_impl->_webSecurityEnabled = initParams->WebSecurityEnabled; - m_impl->_javascriptClipboardAccessEnabled = initParams->JavascriptClipboardAccessEnabled; - m_impl->_mediaStreamEnabled = initParams->MediaStreamEnabled; - m_impl->_smoothScrollingEnabled = initParams->SmoothScrollingEnabled; - m_impl->_ignoreCertificateErrorsEnabled = initParams->IgnoreCertificateErrorsEnabled; - m_impl->_notificationsEnabled = initParams->NotificationsEnabled; - - m_impl->_zoom = initParams->Zoom; - m_impl->_minWidth = initParams->MinWidth; - m_impl->_minHeight = initParams->MinHeight; - m_impl->_maxWidth = initParams->MaxWidth; - m_impl->_maxHeight = initParams->MaxHeight; - - //these handlers are ALWAYS hooked up - m_impl->_webMessageReceivedCallback = initParams->WebMessageReceivedHandler; - m_impl->_resizedCallback = initParams->ResizedHandler; - m_impl->_maximizedCallback = initParams->MaximizedHandler; - m_impl->_restoredCallback = initParams->RestoredHandler; - m_impl->_minimizedCallback = initParams->MinimizedHandler; - m_impl->_movedCallback = initParams->MovedHandler; - m_impl->_closingCallback = initParams->ClosingHandler; - m_impl->_closedCallback = initParams->ClosedHandler; - m_impl->_focusInCallback = initParams->FocusInHandler; - m_impl->_focusOutCallback = initParams->FocusOutHandler; - m_impl->_customSchemeCallback = initParams->CustomSchemeHandler; - - //copy strings from the fixed size array passed, but only if they have a value. - for (int i = 0; i < 16; ++i) { - if (initParams->CustomSchemeNames[i] != nullptr) - m_impl->_customSchemeNames.emplace_back(ToUTF16String(initParams->CustomSchemeNames[i])); - } - - m_impl->_parent = initParams->ParentInstance; - - int normalizedWidth = initParams->Width; - int normalizedHeight = initParams->Height; - int normalizedLeft = initParams->Left; - int normalizedTop = initParams->Top; - bool centerOnInitialize = initParams->CenterOnInitialize; - - if (initParams->UseOsDefaultSize) { - normalizedWidth = CW_USEDEFAULT; - normalizedHeight = CW_USEDEFAULT; - } - else { - if (normalizedWidth < 0) - normalizedWidth = CW_USEDEFAULT; - if (normalizedHeight < 0) - normalizedHeight = CW_USEDEFAULT; - } - - if (initParams->UseOsDefaultLocation) { - normalizedLeft = CW_USEDEFAULT; - normalizedTop = CW_USEDEFAULT; - } - - if (initParams->FullScreen) { - normalizedLeft = 0; - normalizedTop = 0; - normalizedWidth = GetSystemMetrics(SM_CXSCREEN); - normalizedHeight = GetSystemMetrics(SM_CYSCREEN); - } - - if (initParams->Chromeless) { - if (normalizedLeft == CW_USEDEFAULT && normalizedTop == CW_USEDEFAULT) - centerOnInitialize = true; - if (normalizedLeft == CW_USEDEFAULT) - normalizedLeft = 0; - if (normalizedTop == CW_USEDEFAULT) - normalizedTop = 0; - if (normalizedHeight == CW_USEDEFAULT) - normalizedHeight = 600; - if (normalizedWidth == CW_USEDEFAULT) - normalizedWidth = 800; - } - - if (normalizedHeight > initParams->MaxHeight) - normalizedHeight = initParams->MaxHeight; - if (normalizedHeight < initParams->MinHeight && initParams->MinHeight > 0) - normalizedHeight = initParams->MinHeight; - if (normalizedWidth > initParams->MaxWidth) - normalizedWidth = initParams->MaxWidth; - if (normalizedWidth < initParams->MinWidth && initParams->MinWidth > 0) - normalizedWidth = initParams->MinWidth; - +std::string WideToUtf8(const AutoString source) { + if (source == nullptr) + return {}; - const HWND parentWindowHandle = ResolveParentWindowHandle(m_impl->_parent); - m_impl->_pendingOwnerHwnd = parentWindowHandle; + const size_t utf16Length = wcslen(source); + if (utf16Length == 0) + return {}; - //Create the window - const HINSTANCE windowInstance = _hInstance.load(std::memory_order_acquire); - m_impl->_hWnd = CreateWindowEx( - initParams->Transparent ? WS_EX_LAYERED : 0, //WS_EX_OVERLAPPEDWINDOW, //An optional extended window style. - CLASS_NAME, //Window class - m_impl->_windowTitle.c_str(), //Window text - initParams->Chromeless || initParams->FullScreen ? WS_POPUP : WS_OVERLAPPEDWINDOW, //Window style + const auto* utf16 = reinterpret_cast(source); + if (const auto validation = simdutf::validate_utf16_with_errors(utf16, utf16Length); validation.is_err()) + return {}; - // Size and position - normalizedLeft, normalizedTop, normalizedWidth, normalizedHeight, - - nullptr, //Parent window handle is set after creation via GWLP_HWNDPARENT to avoid cross-thread create-time interactions. - nullptr, //Menu - windowInstance, //Instance handle - this //Additional application data + std::string utf8(simdutf::utf8_length_from_utf16(utf16, utf16Length), '\0'); + const size_t written = simdutf::convert_valid_utf16_to_utf8( + utf16, + utf16Length, + utf8.data() ); + utf8.resize(written); - ApplyPendingOwnerWindow(m_impl.get(), L"ctor"); - - if (initParams->WindowIconFile != nullptr) { - SetIconFile(initParams->WindowIconFile); - } - - - if (centerOnInitialize) - Center(); - - if (initParams->Minimized) - SetMinimized(true); - - if (initParams->Maximized) - SetMaximized(true); - - SetResizable(initParams->Resizable); - - if (initParams->Topmost) - SetTopmost(true); - - if (initParams->NotificationsEnabled) { - if (!m_impl->_notificationRegistrationId.empty()) - WinToast::instance()->setAppUserModelId(m_impl->_notificationRegistrationId.c_str()); - - m_impl->_toastHandler = std::make_unique(this); - WinToast::instance()->initialize(); - } - - m_impl->_dialog = std::make_unique(this); - - bool isAlreadyShown = initParams->Minimized || initParams->Maximized; - Show(isAlreadyShown); -} - -InfiniFrameWindow::~InfiniFrameWindow() { -} - -HWND InfiniFrameWindow::getHwnd() { - return m_impl->_hWnd; + return utf8; } +bool EnsureDirectoryWritable(const std::wstring& directoryPath) { + if (directoryPath.empty()) + return false; -LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { - switch (uMsg) { - case WM_NCCREATE: { - const auto* createParams = reinterpret_cast(lParam); - auto* instance = reinterpret_cast(createParams->lpCreateParams); - SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast(instance)); - return TRUE; - } - case WM_CREATE: { - EnableDarkMode(hwnd, true); - if (IsDarkModeEnabled()) - RefreshNonClientArea(hwnd); - break; - } - case WM_DPICHANGED: { - RECT* newWindowRect = reinterpret_cast(lParam); - - SetWindowPos( - hwnd, - nullptr, - newWindowRect->left, - newWindowRect->top, - newWindowRect->right - newWindowRect->left, - newWindowRect->bottom - newWindowRect->top, - SWP_NOZORDER | SWP_NOACTIVATE - ); - - return 0; - } - case WM_SETTINGCHANGE: { - if (IsColorSchemeChange(lParam)) - SendMessageW(hwnd, WM_THEMECHANGED, 0, 0); - - break; - } - case WM_THEMECHANGED: { - EnableDarkMode(hwnd, IsDarkModeEnabled()); - RefreshNonClientArea(hwnd); - InvalidateRect(hwnd, nullptr, TRUE); - break; - } - case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - - // Fill the background with the current theme color - if (IsDarkModeEnabled()) { - FillRect(hdc, &ps.rcPaint, detail::BrushManager::instance().dark()); - } - else { - FillRect(hdc, &ps.rcPaint, detail::BrushManager::instance().light()); - } - - EndPaint(hwnd, &ps); - break; - } - case WM_ACTIVATE: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); - if (instance) { - if (LOWORD(wParam) == WA_INACTIVE) { - instance->InvokeFocusOut(); - } - else { - instance->FocusWebView2(); - instance->InvokeFocusIn(); - - return 0; - } - } - break; - } - case WM_CLOSE: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); - if (instance) { - TraceTeardown(L"WM_CLOSE hwnd=%p instance=%p", hwnd, instance); - bool doNotClose = instance->InvokeClose(); - - if (!doNotClose) { - // On Windows ARM64 we observed occasional access violations during teardown when - // owner/owned windows live on different UI threads. Detach owner linkage before - // destruction to avoid cross-thread owner-chain teardown races. - SetLastError(0); - const LONG_PTR previousOwner = SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, 0); - const DWORD ownerDetachError = GetLastError(); - if (previousOwner != 0 || ownerDetachError == 0) { - TraceTeardown( - L"WM_CLOSE detached owner hwnd=%p prevOwner=%p err=%lu", - hwnd, - reinterpret_cast(previousOwner), - ownerDetachError - ); - } - - DestroyWindow(hwnd); - } - } - - return 0; - } - case WM_DESTROY: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); - if (instance) { - instance->m_impl->_isClosingOrClosed.store(true, std::memory_order_release); - TraceTeardown(L"WM_DESTROY begin hwnd=%p instance=%p", hwnd, instance); - instance->CloseWebView(); - instance->InvokeClosed(); - TraceTeardown(L"WM_DESTROY end hwnd=%p instance=%p", hwnd, instance); - } - // Terminate the message loop of the thread that owns this window - if (hwnd == messageLoopRootWindowHandle) - PostQuitMessage(0); - - return 0; - } - case WM_NCDESTROY: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); - if (instance) { - instance->m_impl->_isClosingOrClosed.store(true, std::memory_order_release); - instance->m_impl->_hWnd = nullptr; - } - TraceTeardown(L"WM_NCDESTROY hwnd=%p instance=%p", hwnd, instance); - SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); - break; - } - case WM_USER_INVOKE: { - auto callback = reinterpret_cast(wParam); - auto* waitInfo = reinterpret_cast(lParam); - - if (waitInfo == nullptr) { - if (callback) - callback(); - return 0; - } - - bool deleteWaitInfo = false; - { - std::lock_guard guard(waitInfo->mutex); - if (!waitInfo->isAbandoned && callback) - callback(); - waitInfo->isCompleted = true; - deleteWaitInfo = waitInfo->isAbandoned; - } - - waitInfo->completionNotifier.notify_one(); - - if (deleteWaitInfo) - delete waitInfo; - return 0; - } - case WM_GETMINMAXINFO: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); - if (instance == nullptr) - return 0; - - MINMAXINFO* mmi = reinterpret_cast(lParam); - if (instance->m_impl->_minWidth > 0) - mmi->ptMinTrackSize.x = instance->m_impl->_minWidth; - if (instance->m_impl->_minHeight > 0) - mmi->ptMinTrackSize.y = instance->m_impl->_minHeight; - if (instance->m_impl->_maxWidth < INT_MAX) - mmi->ptMaxTrackSize.x = instance->m_impl->_maxWidth; - if (instance->m_impl->_maxHeight < INT_MAX) - mmi->ptMaxTrackSize.y = instance->m_impl->_maxHeight; - return 0; - } - case WM_SIZE: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); - if (instance) { - instance->RefitContent(); - int width, height; - instance->GetSize(&width, &height); - instance->InvokeResize(width, height); - - if (LOWORD(wParam) == SIZE_MAXIMIZED) { - instance->InvokeMaximized(); - } - else if (LOWORD(wParam) == SIZE_RESTORED) { - instance->InvokeRestored(); - } - else if (LOWORD(wParam) == SIZE_MINIMIZED) { - instance->InvokeMinimized(); - } - } - return 0; - } - case WM_MOVE: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); - if (instance) { - int x, y; - instance->GetPosition(&x, &y); - instance->InvokeMove(x, y); - } - return 0; - } - } + std::error_code createError; + std::filesystem::create_directories(directoryPath, createError); + if (createError) + return false; - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -void InfiniFrameWindow::CloseWebView() { - m_impl->_isClosingOrClosed.store(true, std::memory_order_release); - const bool deferEnvironmentRelease = - m_impl->_isWebView2Initializing && m_impl->_webviewController == nullptr; - TraceTeardown( - L"CloseWebView begin instance=%p hwnd=%p controller=%p webview=%p env=%p", - this, - m_impl->_hWnd, - m_impl->_webviewController.get(), - m_impl->_webviewWindow.get(), - m_impl->_webviewEnvironment.get() + const std::wstring probePath = std::format( + L"{}\\{}.tmp", + directoryPath, + std::format(L".infiniframe-wv2-write-check-{}-{}-{}", GetCurrentProcessId(), GetCurrentThreadId(), GetTickCount64()) ); - // Keep teardown non-blocking in WM_DESTROY path: Close() the controller first and - // avoid synchronous event unsubscription / Stop() calls that can stall shutdown. - if (m_impl->_webviewController != nullptr) { - m_impl->_webviewController->Close(); - m_impl->_webviewController = nullptr; - } + HANDLE probeHandle = CreateFileW( + probePath.c_str(), + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + CREATE_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY, + nullptr + ); - m_impl->_webviewWindow = nullptr; + if (probeHandle == INVALID_HANDLE_VALUE) + return false; - m_impl->_hasWebMessageReceivedToken = false; - m_impl->_hasWebResourceRequestedToken = false; - m_impl->_hasPermissionRequestedToken = false; - m_impl->_webMessageReceivedToken = {}; - m_impl->_webResourceRequestedTokenForCustomScheme = {}; - m_impl->_permissionRequestedToken = {}; + CloseHandle(probeHandle); + DeleteFileW(probePath.c_str()); + return true; +} - if (m_impl->_webviewEnvironment != nullptr && !deferEnvironmentRelease) { - m_impl->_webviewEnvironment = nullptr; - } +InfiniFrameWindow* LookupWindowInstance(const HWND hwnd) { + return reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); +} - m_impl->_isInitialized = false; - if (!deferEnvironmentRelease) - m_impl->_isWebView2Initializing = false; +HWND ResolveParentWindowHandle(InfiniFrameWindow* parent) { + if (parent == nullptr) + return nullptr; - if (deferEnvironmentRelease) { - TraceTeardown( - L"CloseWebView deferring environment release instance=%p env=%p", - this, - m_impl->_webviewEnvironment.get() - ); - } + HWND parentHwnd = parent->getHwnd(); + if (parentHwnd == nullptr || !IsWindow(parentHwnd)) + return nullptr; - TraceTeardown(L"CloseWebView end instance=%p", this); + return parentHwnd; } - void InfiniFrameWindow::WaitForExit() { ApplyPendingOwnerWindow(m_impl.get(), L"wait_for_exit"); messageLoopRootWindowHandle = m_impl->_hWnd; TraceTeardown(L"WaitForExit start instance=%p hwnd=%p", this, m_impl->_hWnd); - // Run the message loop MSG msg = {}; while (true) { const int getMessageResult = GetMessage(&msg, nullptr, 0, 0); @@ -775,824 +198,3 @@ void InfiniFrameWindow::WaitForExit() { messageLoopRootWindowHandle = nullptr; TraceTeardown(L"WaitForExit end instance=%p hwnd=%p", this, m_impl->_hWnd); } - - -void InfiniFrameWindow::Invoke(ACTION callback) { - if (!callback) - return; - - if (m_impl->_hWnd == nullptr || !IsWindow(m_impl->_hWnd)) - return; - - auto* waitInfo = new InvokeWaitInfo(); - if (!PostMessage( - m_impl->_hWnd, WM_USER_INVOKE, reinterpret_cast(callback), reinterpret_cast(waitInfo) - )) { - delete waitInfo; - return; - } - - std::unique_lock uLock(waitInfo->mutex); - const bool completed = waitInfo->completionNotifier.wait_for( - uLock, - std::chrono::seconds(15), - [&] { - return waitInfo->isCompleted; - } - ); - - if (!completed) { - bool deleteWaitInfo = false; - if (waitInfo->isCompleted) - deleteWaitInfo = true; - else - waitInfo->isAbandoned = true; - - uLock.unlock(); - - if (deleteWaitInfo) - delete waitInfo; - - OutputDebugStringW(L"InfiniFrameWindow::Invoke timed out waiting for UI thread callback.\n"); - return; - } - - uLock.unlock(); - delete waitInfo; -} - -std::string InfiniFrameWindow::ToUTF8String(const AutoString source) const { - return WideToUtf8(source); -} - -std::wstring InfiniFrameWindow::ToUTF16String(const AutoString source) const { - return Utf8ToWide(source); -} - -void InfiniFrameWindow::AttachWebView() { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return; - - if (m_impl->_isWebView2Initializing || m_impl->_isInitialized) - return; - m_impl->_isWebView2Initializing = true; - - std::wstring configuredRuntimePath; - { - std::lock_guard lock(webview2RuntimePathMutex); - configuredRuntimePath = _webview2RuntimePath; - } - PCWSTR runtimePath = configuredRuntimePath.empty() ? nullptr : configuredRuntimePath.c_str(); - - std::wstring startupString; - if (!m_impl->_userAgent.empty()) - startupString += L"--user-agent=\"" + m_impl->_userAgent + L"\" "; - if (m_impl->_mediaAutoplayEnabled) - startupString += L"--autoplay-policy=no-user-gesture-required "; - if (m_impl->_fileSystemAccessEnabled) - startupString += L"--allow-file-access-from-files "; - if (!m_impl->_webSecurityEnabled) - startupString += L"--disable-web-security "; - if (m_impl->_javascriptClipboardAccessEnabled) - startupString += L"--enable-javascript-clipboard-access "; - if (m_impl->_mediaStreamEnabled) - startupString += L"--enable-usermedia-screen-capturing "; - if (!m_impl->_smoothScrollingEnabled) - startupString += L"--disable-smooth-scrolling "; - if (m_impl->_ignoreCertificateErrorsEnabled) - startupString += L"--ignore-certificate-errors "; - if (!m_impl->_browserControlInitParameters.empty()) - startupString += m_impl->_browserControlInitParameters; //e.g.--hide-scrollbars - - auto options = Microsoft::WRL::Make(); - if (startupString.length() > 0) - options->put_AdditionalBrowserArguments(startupString.c_str()); - - bool requiresAppSchemeRegistration = std::any_of( - m_impl->_customSchemeNames.begin(), - m_impl->_customSchemeNames.end(), - [](const std::wstring& schemeName) { - return _wcsicmp(schemeName.c_str(), L"app") == 0; - } - ); - bool appSchemeRegistrationSupported = false; - - // Register custom schemes with WebView2 so top-level navigations like app://... are allowed. - if (!m_impl->_customSchemeNames.empty()) { - wil::com_ptr options4; - if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&options4))) && options4) { - appSchemeRegistrationSupported = true; - std::vector> registrations; - registrations.reserve(m_impl->_customSchemeNames.size()); - - for (const auto& schemeName : m_impl->_customSchemeNames) { - auto registration = Microsoft::WRL::Make(schemeName.c_str()); - if (!registration) - continue; - - // Only the embedded-assets scheme uses app://localhost/... and should be - // treated as secure with an authority component. - if (_wcsicmp(schemeName.c_str(), L"app") == 0) { - registration->put_HasAuthorityComponent(TRUE); - registration->put_TreatAsSecure(TRUE); - } - registrations.emplace_back(registration); - } - - if (!registrations.empty()) { - std::vector rawRegistrations; - rawRegistrations.reserve(registrations.size()); - for (auto& registration : registrations) - rawRegistrations.emplace_back(registration.get()); - - options4->SetCustomSchemeRegistrations( - static_cast(rawRegistrations.size()), - rawRegistrations.data() - ); - } - } - } - - if (requiresAppSchemeRegistration && !appSchemeRegistrationSupported) { - MessageBox( - m_impl->_hWnd, - L"This app requires WebView2 custom scheme registration for app://localhost/. Please update WebView2 Runtime to a version that supports ICoreWebView2EnvironmentOptions4.", - L"WebView2 Runtime Too Old", - MB_OK | MB_ICONERROR - ); - m_impl->_isWebView2Initializing = false; - return; - } - - PCWSTR userDataPath = nullptr; - if (!m_impl->_temporaryFilesPath.empty()) { - if (EnsureDirectoryWritable(m_impl->_temporaryFilesPath)) - userDataPath = m_impl->_temporaryFilesPath.c_str(); - else - TraceTeardown( - L"AttachWebView: temporary user-data path is not writable. Falling back to default path. path=%ls", - m_impl->_temporaryFilesPath.c_str() - ); - } - - HRESULT envResult = CreateCoreWebView2EnvironmentWithOptions( - runtimePath, - userDataPath, - options.Get(), - Callback< - ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>( - [this]( - const HRESULT result, - ICoreWebView2Environment* env - ) -> HRESULT { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { - m_impl->_isWebView2Initializing = false; - m_impl->_webviewEnvironment = nullptr; - TraceTeardown(L"CreateEnvironment callback while closing; ignoring"); - return S_OK; - } - if (result != S_OK) { - m_impl->_isWebView2Initializing = false; - TraceTeardown(L"CreateEnvironment callback failed hr=0x%08X", static_cast(result)); - return result; - } - if (env == nullptr) { - m_impl->_isWebView2Initializing = false; - return E_POINTER; - } - HRESULT envResult = env->QueryInterface( - &m_impl->_webviewEnvironment - ); - if (envResult != S_OK) { - m_impl->_isWebView2Initializing = false; - return envResult; - } - - const HRESULT createControllerHr = env->CreateCoreWebView2Controller( - m_impl->_hWnd, - Callback< - ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>( - [this]( - const HRESULT result, - ICoreWebView2Controller* controller - ) -> - HRESULT { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { - if (controller != nullptr) - controller->Close(); - m_impl->_webviewController = nullptr; - m_impl->_webviewWindow = nullptr; - m_impl->_webviewEnvironment = nullptr; - m_impl->_isWebView2Initializing = false; - TraceTeardown(L"CreateController callback while closing; ignoring"); - return S_OK; - } - if (result != S_OK) { - m_impl->_isWebView2Initializing = false; - TraceTeardown(L"CreateController callback failed hr=0x%08X", static_cast(result)); - return result; - } - if (controller == nullptr) { - m_impl->_isWebView2Initializing = false; - return E_POINTER; - } - - HRESULT envResult = controller-> - QueryInterface( - &m_impl-> - _webviewController - ); - if (envResult != S_OK) { - m_impl->_isWebView2Initializing = false; - return envResult; - } - m_impl->_webviewController->get_CoreWebView2(&m_impl->_webviewWindow); - if (!m_impl->_webviewWindow) { - m_impl->_isWebView2Initializing = false; - return E_FAIL; - } - - const auto js_wide = Embedded::InfiniFrameJsUtf16(); - OutputDebugStringW(std::format(L"[InfiniFrame] Bridge script length: {} chars\n", js_wide.size()).c_str()); - - // AddScriptToExecuteOnDocumentCreated is async: the script is not - // registered in the browser process until the completion callback fires. - // We must not navigate until then, otherwise fast local navigations - // (e.g., app://localhost/) reach ContentLoading before the bridge script - // exists, and Blazor's Boot.WebView.ts throws because - // window.external.receiveMessage is undefined. - // - // If script registration fails for any reason (e.g., empty resource), - // we fall through and navigate anyway so the page still loads. - struct NavigateOnce { - InfiniFrameWindow* self; - bool fired = false; - void navigate() { - if (fired) return; - fired = true; - if (!self->m_impl->_startUrl.empty()) - self->m_impl->_webviewWindow->Navigate(self->m_impl->_startUrl.c_str()); - else if (!self->m_impl->_startString.empty()) - self->m_impl->_webviewWindow->NavigateToString(self->m_impl->_startString.c_str()); - else { - MessageBox(nullptr, - L"Neither StartUrl nor StartString was specified", - L"Native Initialization Failed", MB_OK); - exit(0); - } - } - }; - auto nav = std::make_shared(NavigateOnce{this}); - - wil::com_ptr - settings; - HRESULT settingsResult = m_impl-> - _webviewWindow->get_Settings( - &settings - ); - if (FAILED(settingsResult) || ! - settings) { - return FAILED(settingsResult) - ? settingsResult - : E_FAIL; - } - settings-> - put_AreHostObjectsAllowed( - TRUE - ); - settings->put_IsScriptEnabled( - TRUE - ); - settings-> - put_AreDefaultScriptDialogsEnabled( - TRUE - ); - settings->put_IsWebMessageEnabled( - TRUE - ); - - EventRegistrationToken - webMessageToken; - - m_impl->_webviewWindow-> - add_WebMessageReceived( - Callback< - ICoreWebView2WebMessageReceivedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2WebMessageReceivedEventArgs - * args - ) -> HRESULT { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return S_OK; - - wil::unique_cotaskmem_string - message; - wil::unique_cotaskmem_string - source; - args-> - TryGetWebMessageAsString( - &message - ); - args-> - get_Source( - &source - ); - if ( - (source.get() == nullptr - || source.get()[0] == L'\0') - && m_impl->_webviewWindow != nullptr - ) { - m_impl-> - _webviewWindow-> - get_Source( - &source - ); - } - m_impl-> - _webMessageReceivedCallback( - message. - get(), - source. - get() - ); - return S_OK; - } - ).Get(), - &webMessageToken - ); - m_impl->_webMessageReceivedToken = webMessageToken; - m_impl->_hasWebMessageReceivedToken = true; - - EventRegistrationToken - webResourceRequestedToken; - auto webview23 = m_impl->_webviewWindow.try_query(); - if (webview23) { - webview23->AddWebResourceRequestedFilterWithRequestSourceKinds( - L"*", - COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, - COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL - ); - } - else { - m_impl->_webviewWindow-> - AddWebResourceRequestedFilter( - L"*", - COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL - ); - } - m_impl->_webviewWindow-> - add_WebResourceRequested( - Callback< - ICoreWebView2WebResourceRequestedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2WebResourceRequestedEventArgs - * args - ) { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return S_OK; - - wil::com_ptr< - ICoreWebView2WebResourceRequest> - req; - if (FAILED( - args-> - get_Request( - &req - ) - ) - || ! - req) - return S_OK; - - wil::unique_cotaskmem_string - uri; - req->get_Uri(&uri); - std::wstring - uriString = uri - .get(); - wil::com_ptr - requestHeaders; - std::wstring requestOrigin; - if (SUCCEEDED(req->get_Headers(&requestHeaders)) && requestHeaders) { - wil::unique_cotaskmem_string originHeaderValue; - if (SUCCEEDED( - requestHeaders->GetHeader(L"Origin", &originHeaderValue) - ) - && originHeaderValue.get() != nullptr - && originHeaderValue.get()[0] != L'\0') { - requestOrigin = originHeaderValue.get(); - } - } - - if (uriString.find(L"/_framework/blazor.modules.json") != - std::wstring::npos) { - static constexpr BYTE emptyModuleArray[] = {'[', ']'}; - wil::com_ptr dataStream; - dataStream.attach( - SHCreateMemStream(emptyModuleArray, sizeof(emptyModuleArray)) - ); - if (!dataStream) - return S_OK; - - std::wstring responseHeaders = L"Content-Type: application/json"; - responseHeaders += - L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; - responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; - if (!requestOrigin.empty()) { - responseHeaders += L"\r\nAccess-Control-Allow-Origin: " + - requestOrigin; - responseHeaders += - L"\r\nAccess-Control-Allow-Credentials: true"; - responseHeaders += L"\r\nVary: Origin"; - } - else { - responseHeaders += L"\r\nAccess-Control-Allow-Origin: *"; - } - - wil::com_ptr response; - m_impl->_webviewEnvironment->CreateWebResourceResponse( - dataStream.get(), - 200, - L"OK", - responseHeaders.c_str(), - &response - ); - args->put_Response(response.get()); - return S_OK; - } - size_t colonPos = - uriString.find( - L':', 0 - ); - if (colonPos > 0) { - std::wstring - scheme = - uriString - .substr( - 0, - colonPos - ); - auto it = - std::find( - m_impl - -> - _customSchemeNames - .begin(), - m_impl - -> - _customSchemeNames - .end(), - scheme - ); - - if (it != - m_impl-> - _customSchemeNames - .end() && - m_impl-> - _customSchemeCallback - != - nullptr) { - int - numBytes; - AutoString - contentType - = nullptr; - wil::unique_cotaskmem - dotNetResponse( - m_impl - -> - _customSchemeCallback( - const_cast - - (uriString - .c_str()), - &numBytes, - &contentType - ) - ); - auto - freeContentType - = wil::scope_exit( - [& - contentType - ] { - CoTaskMemFree( - contentType - ); - } - ); - - if ( - dotNetResponse - != - nullptr - && - contentType - != - nullptr) { - std::wstring - contentTypeWS - = contentType; - - wil::com_ptr - - dataStream; - dataStream - .attach( - SHCreateMemStream( - reinterpret_cast - - (dotNetResponse - .get()), - numBytes - ) - ); - if (! - dataStream) - return - S_OK; - wil::com_ptr - - response; - std::wstring responseHeaders = L"Content-Type: " + - contentTypeWS; - responseHeaders += - L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; - responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; - if (!requestOrigin.empty()) { - responseHeaders += L"\r\nAccess-Control-Allow-Origin: " - + requestOrigin; - responseHeaders += - L"\r\nAccess-Control-Allow-Credentials: true"; - responseHeaders += L"\r\nVary: Origin"; - } - else { - responseHeaders += - L"\r\nAccess-Control-Allow-Origin: *"; - } - m_impl - -> - _webviewEnvironment - -> - CreateWebResourceResponse( - dataStream - .get(), - 200, - L"OK", - responseHeaders.c_str(), - &response - ); - args-> - put_Response( - response - .get() - ); - } - } - } - - return S_OK; - } - ).Get(), - &webResourceRequestedToken - ); - m_impl->_webResourceRequestedTokenForCustomScheme = webResourceRequestedToken; - m_impl->_hasWebResourceRequestedToken = true; - - EventRegistrationToken - permissionRequestedToken; - m_impl->_webviewWindow-> - add_PermissionRequested( - Callback< - ICoreWebView2PermissionRequestedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2PermissionRequestedEventArgs - * args - ) -> HRESULT { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return S_OK; - - if (m_impl-> - _grantBrowserPermissions) - args-> - put_State( - COREWEBVIEW2_PERMISSION_STATE_ALLOW - ); - return S_OK; - } - ) - .Get(), - &permissionRequestedToken - ); - m_impl->_permissionRequestedToken = permissionRequestedToken; - m_impl->_hasPermissionRequestedToken = true; - - if (m_impl->_contextMenuEnabled == - false) - SetContextMenuEnabled(false); - - if (m_impl->_zoomEnabled == false) - SetZoomEnabled(false); - - if (m_impl->_devToolsEnabled == - false) - SetDevToolsEnabled(false); - - if (m_impl->_transparentEnabled == - true) - SetTransparentEnabled(true); - - if (m_impl->_zoom != 100) - SetZoom(m_impl->_zoom); - - HRESULT addScriptHr = m_impl->_webviewWindow->AddScriptToExecuteOnDocumentCreated( - js_wide.c_str(), - Callback( - [nav, this](HRESULT errorCode, LPCWSTR id) -> HRESULT { - OutputDebugStringW(std::format(L"[InfiniFrame] AddScriptToExecuteOnDocumentCreated callback: hr=0x{:08X} id={}\n", (unsigned)errorCode, id ? id : L"(null)").c_str()); - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return S_OK; - nav->navigate(); - return S_OK; - } - ).Get() - ); - - // If AddScriptToExecuteOnDocumentCreated itself failed synchronously - // (e.g., empty script string on some WebView2 versions), navigate now - // so the page is not left blank. - if (FAILED(addScriptHr)) - nav->navigate(); - - RefitContent(); - - FocusWebView2(); - - // Re-apply if topmost was requested - if (m_impl->_topmost) - SetTopmost(true); - - m_impl->_isInitialized = true; - m_impl->_isWebView2Initializing = false; - return S_OK; - } - ).Get() - ); - if (FAILED(createControllerHr)) - m_impl->_isWebView2Initializing = false; - - return createControllerHr; - } - ).Get() - ); - - if (envResult != S_OK) { - m_impl->_isWebView2Initializing = false; - _com_error err(envResult); - LPCTSTR errMsg = err.ErrorMessage(); - MessageBox(m_impl->_hWnd, errMsg, L"Error instantiating webview", MB_OK); - } -} - - -bool InfiniFrameWindow::EnsureWebViewIsInstalled() { - LPWSTR versionInfo = nullptr; - HRESULT ensureInstalledResult = GetAvailableCoreWebView2BrowserVersionString(nullptr, &versionInfo); - if (versionInfo != nullptr) - CoTaskMemFree(versionInfo); - - if (ensureInstalledResult != S_OK) - return InstallWebView2(); - - return true; -} - -bool InfiniFrameWindow::InstallWebView2() { - auto srcURL = L"https://go.microsoft.com/fwlink/p/?LinkId=2124703"; - auto destFile = L"MicrosoftEdgeWebview2Setup.exe"; - - if (S_OK == URLDownloadToFile(nullptr, srcURL, destFile, 0, nullptr)) { - std::wstring command = L"MicrosoftEdgeWebview2Setup.exe"; - - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - bool success = CreateProcess( - nullptr, // No module name (use command line) - command.data(), // Command line - nullptr, // Process handle not inheritable - nullptr, // Thread handle not inheritable - FALSE, // Set handle inheritance to FALSE - 0, // No creation flags - nullptr, // Use parent's environment block - nullptr, // Use parent's starting directory - &si, // Pointer to STARTUPINFO structure - &pi - ); // Pointer to PROCESS_INFORMATION structure - - if (success) { - // wait for the installation to complete - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - - return success; - } - - return false; -} - -void InfiniFrameWindow::RefitContent() { - if (m_impl->_webviewController) { - RECT bounds; - GetClientRect(m_impl->_hWnd, &bounds); - m_impl->_webviewController->put_Bounds(bounds); - } -} - -void InfiniFrameWindow::FocusWebView2() { - if (m_impl->_webviewController) { - m_impl->_webviewController->MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC); - } -} - -void InfiniFrameWindow::NotifyWebView2WindowMove() { - if (m_impl->_webviewController) { - m_impl->_webviewController->NotifyParentWindowPositionChanged(); - } -} - -void InfiniFrameWindow::ClearBrowserAutoFill() { - if (!m_impl->_webviewWindow) - return; - - auto webview15 = m_impl->_webviewWindow.try_query(); - if (webview15) { - wil::com_ptr profile; - webview15->get_Profile(&profile); - auto profile2 = profile.try_query(); - - if (profile2) { - COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds = - (COREWEBVIEW2_BROWSING_DATA_KINDS) - ( - COREWEBVIEW2_BROWSING_DATA_KINDS_GENERAL_AUTOFILL | - COREWEBVIEW2_BROWSING_DATA_KINDS_PASSWORD_AUTOSAVE - ); - - profile2->ClearBrowsingData( - dataKinds, - Callback( - [this]( - HRESULT - ) - -> HRESULT { - return S_OK; - } - ) - .Get() - ); - } - } -} - -void InfiniFrameWindow::SetWebView2RuntimePath(const AutoString pathToWebView2) { - if (pathToWebView2 == nullptr) - return; - - std::wstring widePath = Utf8ToWide(pathToWebView2); - std::lock_guard lock(webview2RuntimePathMutex); - wcsncpy_s(_webview2RuntimePath, widePath.c_str(), _countof(_webview2RuntimePath)); -} - -void InfiniFrameWindow::Show(const bool isAlreadyShown) { - if (!isAlreadyShown) - ShowWindow(m_impl->_hWnd, SW_SHOWDEFAULT); - - UpdateWindow(m_impl->_hWnd); - - // WebView2 must be created after the window is visible. - if (!m_impl->_webviewController) { - bool hasConfiguredRuntimePath = false; - { - std::lock_guard lock(webview2RuntimePathMutex); - hasConfiguredRuntimePath = wcsnlen(_webview2RuntimePath, _countof(_webview2RuntimePath)) > 0; - } - if (hasConfiguredRuntimePath || EnsureWebViewIsInstalled()) - AttachWebView(); - else - exit(0); - } -} - diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowLifecycle.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowLifecycle.Win32.cpp new file mode 100644 index 000000000..59f8da863 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowLifecycle.Win32.cpp @@ -0,0 +1,264 @@ +#include + +#include "DarkMode.h" +#include "Window.Win32.Context.h" + +using namespace WinToastLib; + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +namespace { + class BrushManager { + public: + static BrushManager& instance() noexcept { + static BrushManager inst; + return inst; + } + + HBRUSH dark() const noexcept { + return static_cast(m_darkBrush.get()); + } + + HBRUSH light() const noexcept { + return static_cast(m_lightBrush.get()); + } + + private: + BrushManager() noexcept { + m_darkBrush.reset(CreateSolidBrush(RGB(0, 0, 0))); + m_lightBrush.reset(CreateSolidBrush(RGB(255, 255, 255))); + } + + ~BrushManager() noexcept = default; + + struct HBRUSHDeleter { + void operator()(void* h) const noexcept { + if (h) + DeleteObject(static_cast(h)); + } + }; + + std::unique_ptr m_darkBrush; + std::unique_ptr m_lightBrush; + }; +} + +HBRUSH GetDarkBrush() { + return BrushManager::instance().dark(); +} + +HBRUSH GetLightBrush() { + return BrushManager::instance().light(); +} + +void InfiniFrameWindow::Register(const HINSTANCE hInstance) { + InitDarkModeSupport(); + + _hInstance.store(hInstance, std::memory_order_release); + + WNDCLASSEX wcx; + wcx.cbSize = sizeof(WNDCLASSEX); + wcx.style = CS_HREDRAW | CS_VREDRAW; + wcx.lpfnWndProc = WindowProc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hInstance = hInstance; + wcx.hIcon = LoadIcon(hInstance, IDI_APPLICATION); + wcx.hCursor = LoadCursor(nullptr, IDC_ARROW); + wcx.hbrBackground = IsDarkModeEnabled() ? GetDarkBrush() : GetLightBrush(); + wcx.lpszMenuName = nullptr; + wcx.lpszClassName = CLASS_NAME; + wcx.hIconSm = LoadIcon(hInstance, IDI_APPLICATION); + + RegisterClassEx(&wcx); + + SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); +} + +InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { + m_impl = std::make_unique(); + if (initParams->Size != sizeof(InfiniFrameInitParams)) { + auto msg = std::format( + L"Initial parameters passed are {} bytes, but expected {} bytes.", + initParams->Size, sizeof(InfiniFrameInitParams) + ); + MessageBox(nullptr, msg.c_str(), L"Native Initialization Failed", MB_OK); + exit(0); + } + + if (initParams->Title != nullptr) { + m_impl->_windowTitle = ToUTF16String(initParams->Title); + if (initParams->NotificationsEnabled) { + WinToast::instance()->setAppName(m_impl->_windowTitle.c_str()); + if (m_impl->_notificationRegistrationId.empty()) + WinToast::instance()->setAppUserModelId(m_impl->_windowTitle.c_str()); + } + } + + if (initParams->StartUrl != nullptr) + m_impl->_startUrl = ToUTF16String(initParams->StartUrl); + + if (initParams->StartString != nullptr) + m_impl->_startString = ToUTF16String(initParams->StartString); + + if (initParams->TemporaryFilesPath != nullptr) + m_impl->_temporaryFilesPath = ToUTF16String(initParams->TemporaryFilesPath); + + if (initParams->UserAgent != nullptr) + m_impl->_userAgent = ToUTF16String(initParams->UserAgent); + + if (initParams->BrowserControlInitParameters != nullptr) + m_impl->_browserControlInitParameters = ToUTF16String(initParams->BrowserControlInitParameters); + + if (initParams->NotificationRegistrationId != nullptr) + m_impl->_notificationRegistrationId = ToUTF16String(initParams->NotificationRegistrationId); + + + m_impl->_transparentEnabled = initParams->Transparent; + m_impl->_contextMenuEnabled = initParams->ContextMenuEnabled; + m_impl->_zoomEnabled = initParams->ZoomEnabled; + m_impl->_devToolsEnabled = initParams->DevToolsEnabled; + m_impl->_grantBrowserPermissions = initParams->GrantBrowserPermissions; + m_impl->_mediaAutoplayEnabled = initParams->MediaAutoplayEnabled; + m_impl->_fileSystemAccessEnabled = initParams->FileSystemAccessEnabled; + m_impl->_webSecurityEnabled = initParams->WebSecurityEnabled; + m_impl->_javascriptClipboardAccessEnabled = initParams->JavascriptClipboardAccessEnabled; + m_impl->_mediaStreamEnabled = initParams->MediaStreamEnabled; + m_impl->_smoothScrollingEnabled = initParams->SmoothScrollingEnabled; + m_impl->_ignoreCertificateErrorsEnabled = initParams->IgnoreCertificateErrorsEnabled; + m_impl->_notificationsEnabled = initParams->NotificationsEnabled; + + m_impl->_zoom = initParams->Zoom; + m_impl->_minWidth = initParams->MinWidth; + m_impl->_minHeight = initParams->MinHeight; + m_impl->_maxWidth = initParams->MaxWidth; + m_impl->_maxHeight = initParams->MaxHeight; + + m_impl->_webMessageReceivedCallback = initParams->WebMessageReceivedHandler; + m_impl->_resizedCallback = initParams->ResizedHandler; + m_impl->_maximizedCallback = initParams->MaximizedHandler; + m_impl->_restoredCallback = initParams->RestoredHandler; + m_impl->_minimizedCallback = initParams->MinimizedHandler; + m_impl->_movedCallback = initParams->MovedHandler; + m_impl->_closingCallback = initParams->ClosingHandler; + m_impl->_closedCallback = initParams->ClosedHandler; + m_impl->_focusInCallback = initParams->FocusInHandler; + m_impl->_focusOutCallback = initParams->FocusOutHandler; + m_impl->_customSchemeCallback = initParams->CustomSchemeHandler; + + for (int i = 0; i < 16; ++i) { + if (initParams->CustomSchemeNames[i] != nullptr) + m_impl->_customSchemeNames.emplace_back(ToUTF16String(initParams->CustomSchemeNames[i])); + } + + m_impl->_parent = initParams->ParentInstance; + + int normalizedWidth = initParams->Width; + int normalizedHeight = initParams->Height; + int normalizedLeft = initParams->Left; + int normalizedTop = initParams->Top; + bool centerOnInitialize = initParams->CenterOnInitialize; + + if (initParams->UseOsDefaultSize) { + normalizedWidth = CW_USEDEFAULT; + normalizedHeight = CW_USEDEFAULT; + } + else { + if (normalizedWidth < 0) + normalizedWidth = CW_USEDEFAULT; + if (normalizedHeight < 0) + normalizedHeight = CW_USEDEFAULT; + } + + if (initParams->UseOsDefaultLocation) { + normalizedLeft = CW_USEDEFAULT; + normalizedTop = CW_USEDEFAULT; + } + + if (initParams->FullScreen) { + normalizedLeft = 0; + normalizedTop = 0; + normalizedWidth = GetSystemMetrics(SM_CXSCREEN); + normalizedHeight = GetSystemMetrics(SM_CYSCREEN); + } + + if (initParams->Chromeless) { + if (normalizedLeft == CW_USEDEFAULT && normalizedTop == CW_USEDEFAULT) + centerOnInitialize = true; + if (normalizedLeft == CW_USEDEFAULT) + normalizedLeft = 0; + if (normalizedTop == CW_USEDEFAULT) + normalizedTop = 0; + if (normalizedHeight == CW_USEDEFAULT) + normalizedHeight = 600; + if (normalizedWidth == CW_USEDEFAULT) + normalizedWidth = 800; + } + + if (normalizedHeight > initParams->MaxHeight) + normalizedHeight = initParams->MaxHeight; + if (normalizedHeight < initParams->MinHeight && initParams->MinHeight > 0) + normalizedHeight = initParams->MinHeight; + if (normalizedWidth > initParams->MaxWidth) + normalizedWidth = initParams->MaxWidth; + if (normalizedWidth < initParams->MinWidth && initParams->MinWidth > 0) + normalizedWidth = initParams->MinWidth; + + + const HWND parentWindowHandle = ResolveParentWindowHandle(m_impl->_parent); + m_impl->_pendingOwnerHwnd = parentWindowHandle; + + const HINSTANCE windowInstance = _hInstance.load(std::memory_order_acquire); + m_impl->_hWnd = CreateWindowEx( + initParams->Transparent ? WS_EX_LAYERED : 0, + CLASS_NAME, + m_impl->_windowTitle.c_str(), + initParams->Chromeless || initParams->FullScreen ? WS_POPUP : WS_OVERLAPPEDWINDOW, + normalizedLeft, normalizedTop, normalizedWidth, normalizedHeight, + nullptr, + nullptr, + windowInstance, + this + ); + + ApplyPendingOwnerWindow(m_impl.get(), L"ctor"); + + if (initParams->WindowIconFile != nullptr) { + SetIconFile(initParams->WindowIconFile); + } + + + if (centerOnInitialize) + Center(); + + if (initParams->Minimized) + SetMinimized(true); + + if (initParams->Maximized) + SetMaximized(true); + + SetResizable(initParams->Resizable); + + if (initParams->Topmost) + SetTopmost(true); + + if (initParams->NotificationsEnabled) { + if (!m_impl->_notificationRegistrationId.empty()) + WinToast::instance()->setAppUserModelId(m_impl->_notificationRegistrationId.c_str()); + + m_impl->_toastHandler = std::make_unique(this); + WinToast::instance()->initialize(); + } + + m_impl->_dialog = std::make_unique(this); + + bool isAlreadyShown = initParams->Minimized || initParams->Maximized; + Show(isAlreadyShown); +} + +InfiniFrameWindow::~InfiniFrameWindow() { +} + +HWND InfiniFrameWindow::getHwnd() { + return m_impl->_hWnd; +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowProc.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowProc.Win32.cpp new file mode 100644 index 000000000..6726a5727 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowProc.Win32.cpp @@ -0,0 +1,151 @@ +#include "DarkMode.h" +#include "Window.Win32.Context.h" + +LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { + switch (uMsg) { + case WM_NCCREATE: { + const auto* createParams = reinterpret_cast(lParam); + auto* instance = reinterpret_cast(createParams->lpCreateParams); + SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast(instance)); + return TRUE; + } + case WM_CREATE: { + EnableDarkMode(hwnd, true); + if (IsDarkModeEnabled()) + RefreshNonClientArea(hwnd); + break; + } + case WM_DPICHANGED: { + RECT* newWindowRect = reinterpret_cast(lParam); + + SetWindowPos( + hwnd, + nullptr, + newWindowRect->left, + newWindowRect->top, + newWindowRect->right - newWindowRect->left, + newWindowRect->bottom - newWindowRect->top, + SWP_NOZORDER | SWP_NOACTIVATE + ); + + return 0; + } + case WM_SETTINGCHANGE: { + if (IsColorSchemeChange(lParam)) + SendMessageW(hwnd, WM_THEMECHANGED, 0, 0); + + break; + } + case WM_THEMECHANGED: { + EnableDarkMode(hwnd, IsDarkModeEnabled()); + RefreshNonClientArea(hwnd); + InvalidateRect(hwnd, nullptr, TRUE); + break; + } + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + if (IsDarkModeEnabled()) { + FillRect(hdc, &ps.rcPaint, GetDarkBrush()); + } + else { + FillRect(hdc, &ps.rcPaint, GetLightBrush()); + } + + EndPaint(hwnd, &ps); + break; + } + case WM_ACTIVATE: { + InfiniFrameWindow * instance = LookupWindowInstance(hwnd); + if (instance) { + if (LOWORD(wParam) == WA_INACTIVE) { + instance->InvokeFocusOut(); + } + else { + instance->FocusWebView2(); + instance->InvokeFocusIn(); + + return 0; + } + } + break; + } + case WM_CLOSE: { + InfiniFrameWindow * instance = LookupWindowInstance(hwnd); + if (instance) { + TraceTeardown(L"WM_CLOSE hwnd=%p instance=%p", hwnd, instance); + bool doNotClose = instance->InvokeClose(); + + if (!doNotClose) { + SetLastError(0); + const LONG_PTR previousOwner = SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, 0); + const DWORD ownerDetachError = GetLastError(); + if (previousOwner != 0 || ownerDetachError == 0) { + TraceTeardown( + L"WM_CLOSE detached owner hwnd=%p prevOwner=%p err=%lu", + hwnd, + reinterpret_cast(previousOwner), + ownerDetachError + ); + } + + DestroyWindow(hwnd); + } + } + + return 0; + } + case WM_DESTROY: { + InfiniFrameWindow * instance = LookupWindowInstance(hwnd); + if (instance) { + instance->m_impl->_isClosingOrClosed.store(true, std::memory_order_release); + TraceTeardown(L"WM_DESTROY begin hwnd=%p instance=%p", hwnd, instance); + instance->CloseWebView(); + instance->InvokeClosed(); + TraceTeardown(L"WM_DESTROY end hwnd=%p instance=%p", hwnd, instance); + } + if (hwnd == messageLoopRootWindowHandle) + PostQuitMessage(0); + + return 0; + } + case WM_NCDESTROY: { + InfiniFrameWindow * instance = LookupWindowInstance(hwnd); + if (instance) { + instance->m_impl->_isClosingOrClosed.store(true, std::memory_order_release); + instance->m_impl->_hWnd = nullptr; + } + TraceTeardown(L"WM_NCDESTROY hwnd=%p instance=%p", hwnd, instance); + SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); + break; + } + case WM_USER_INVOKE: { + auto callback = reinterpret_cast(wParam); + auto* waitInfo = reinterpret_cast(lParam); + + if (waitInfo == nullptr) { + if (callback) + callback(); + return 0; + } + + bool deleteWaitInfo = false; + { + std::lock_guard guard(waitInfo->mutex); + if (!waitInfo->isAbandoned && callback) + callback(); + waitInfo->isCompleted = true; + deleteWaitInfo = waitInfo->isAbandoned; + } + + waitInfo->completionNotifier.notify_one(); + + if (deleteWaitInfo) + delete waitInfo; + return 0; + } + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} From a39e49fd3cc3e9d3b4be1eae030545865a11d616 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 19:01:53 +0200 Subject: [PATCH 04/86] Remove Linux (GTK/WebKit)-specific window implementation and migrate Windows (Win32/WebView2) window initialization logic to a dedicated file. --- .../Native/CMakeLists.txt | 12 +- .../Platform/Linux/Window.Gtk.Internal.h | 5 + .../Native/Platform/Linux/Window.cpp | 232 ------ .../Native/Platform/Linux/WindowCore.Gtk.cpp | 49 ++ .../Linux/WindowInitialization.Gtk.cpp | 180 ++++ .../Platform/Windows/UiDispatcher.Win32.cpp | 24 + .../Platform/Windows/WebView2Attach.Win32.cpp | 578 +++++++++++++ .../Windows/WebView2Controller.Win32.cpp | 57 ++ .../Platform/Windows/WebView2Host.Win32.cpp | 771 ------------------ .../Windows/WebView2Runtime.Win32.cpp | 65 ++ .../Native/Platform/Windows/Window.cpp | 200 ----- .../Platform/Windows/WindowCore.Win32.cpp | 10 + .../Platform/Windows/WindowEncoding.Win32.cpp | 56 ++ .../Windows/WindowOwnership.Win32.cpp | 16 + .../Platform/Windows/WindowStorage.Win32.cpp | 42 + .../Platform/Windows/WindowTracing.Win32.cpp | 42 + 16 files changed, 1134 insertions(+), 1205 deletions(-) delete mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowCore.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowInitialization.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Attach.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Controller.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Runtime.Win32.cpp delete mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowCore.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEncoding.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowOwnership.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowStorage.Win32.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowTracing.Win32.cpp diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index 9daa3ebb2..947dfec61 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -45,19 +45,27 @@ set(TEST_SOURCES ) set(WINDOWS_SOURCES - Platform/Windows/Window.cpp + Platform/Windows/WindowCore.Win32.cpp + Platform/Windows/WindowTracing.Win32.cpp + Platform/Windows/WindowEncoding.Win32.cpp + Platform/Windows/WindowStorage.Win32.cpp + Platform/Windows/WindowOwnership.Win32.cpp Platform/Windows/WindowLifecycle.Win32.cpp Platform/Windows/WindowProc.Win32.cpp Platform/Windows/WindowState.Win32.cpp Platform/Windows/WindowEvents.Win32.cpp Platform/Windows/WebView2Host.Win32.cpp + Platform/Windows/WebView2Runtime.Win32.cpp + Platform/Windows/WebView2Controller.Win32.cpp + Platform/Windows/WebView2Attach.Win32.cpp Platform/Windows/UiDispatcher.Win32.cpp Platform/Windows/DarkMode.cpp Platform/Windows/Dialog.cpp ) set(LINUX_SOURCES - Platform/Linux/Window.cpp + Platform/Linux/WindowCore.Gtk.cpp + Platform/Linux/WindowInitialization.Gtk.cpp Platform/Linux/WindowLifecycle.Gtk.cpp Platform/Linux/WindowState.Gtk.cpp Platform/Linux/WindowEvents.Gtk.cpp diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h index 157498f54..e708906da 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h @@ -35,6 +35,11 @@ struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { void set_webkit_settings(); void set_webkit_customsettings(WebKitSettings* settings); void AddCustomSchemeHandlers(); + void InitializeFromParams(const InfiniFrameInitParams* initParams); + void ConfigureInitialWindow(InfiniFrameWindow* window, InfiniFrameInitParams* initParams); + void ApplyInitialWindowState(InfiniFrameWindow* window, const InfiniFrameInitParams* initParams); + void ConnectWindowSignals(InfiniFrameWindow* window); + void ConnectWebViewSignals(InfiniFrameWindow* window); }; #endif // INFINIFRAME_PLATFORM_LINUX_WINDOW_GTK_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp deleted file mode 100644 index c96551195..000000000 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#ifdef __linux__ -#include "Core/InfiniFrameWindow.h" -#include "Core/InfiniFrameDialog.h" -#include "Utils/Common.h" -#include "Window.Gtk.Internal.h" -#include -#include -#include -#include -#include -#include -#include - -// Forward declarations for GTK signal handlers -gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, gpointer self); -gboolean on_window_state_event(GtkWidget* widget, GdkEventWindowState* event, gpointer self); -gboolean on_widget_deleted(GtkWidget* widget, GdkEvent* event, gpointer self); -void on_widget_destroyed(GtkWidget* widget, gpointer self); -gboolean on_focus_in_event(GtkWidget* widget, GdkEvent* event, gpointer self); -gboolean on_focus_out_event(GtkWidget* widget, GdkEvent* event, gpointer self); -gboolean on_webview_context_menu( - WebKitWebView* web_view, - GtkWidget* default_menu, - WebKitHitTestResult* hit_test_result, - gboolean triggered_with_keyboard, - gpointer user_data - ); -gboolean on_permission_request(WebKitWebView* web_view, WebKitPermissionRequest* request, gpointer user_data); -void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data); -gboolean on_webview_load_failed( - WebKitWebView* web_view, - WebKitLoadEvent load_event, - gchar* failing_uri, - GError* error, - gpointer user_data - ); -void on_webview_process_terminated( - WebKitWebView* web_view, - WebKitWebProcessTerminationReason reason, - gpointer user_data - ); -void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data); - -// --------------------------------------------------------------------------------------------------------------------- -// Constructor / Destructor -// --------------------------------------------------------------------------------------------------------------------- - -InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) : - m_impl(std::make_unique()) { - XInitThreads(); - gtk_init(nullptr, nullptr); - notify_init(initParams->Title); - - if (initParams->Size != sizeof(InfiniFrameInitParams)) { - GtkWidget* dialog = gtk_message_dialog_new( - nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "Initial parameters passed are %i bytes, but expected %lu bytes.", - initParams->Size, sizeof(InfiniFrameInitParams) - ); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - exit(0); - } - - m_impl->_windowTitle = initParams->Title ? initParams->Title : ""; - - if (initParams->StartUrl != nullptr) - m_impl->_startUrl = initParams->StartUrl; - - if (initParams->StartString != nullptr) - m_impl->_startString = initParams->StartString; - - if (initParams->TemporaryFilesPath != nullptr) - m_impl->_temporaryFilesPath = initParams->TemporaryFilesPath; - - if (initParams->UserAgent != nullptr) - m_impl->_userAgent = initParams->UserAgent; - - if (initParams->BrowserControlInitParameters != nullptr) - m_impl->_browserControlInitParameters = initParams->BrowserControlInitParameters; - - m_impl->_transparentEnabled = initParams->Transparent; - m_impl->_contextMenuEnabled = initParams->ContextMenuEnabled; - m_impl->_zoomEnabled = initParams->ZoomEnabled; - m_impl->_devToolsEnabled = initParams->DevToolsEnabled; - m_impl->_grantBrowserPermissions = initParams->GrantBrowserPermissions; - m_impl->_mediaAutoplayEnabled = initParams->MediaAutoplayEnabled; - m_impl->_fileSystemAccessEnabled = initParams->FileSystemAccessEnabled; - m_impl->_webSecurityEnabled = initParams->WebSecurityEnabled; - m_impl->_javascriptClipboardAccessEnabled = initParams->JavascriptClipboardAccessEnabled; - m_impl->_mediaStreamEnabled = initParams->MediaStreamEnabled; - m_impl->_smoothScrollingEnabled = initParams->SmoothScrollingEnabled; - m_impl->_ignoreCertificateErrorsEnabled = initParams->IgnoreCertificateErrorsEnabled; - m_impl->_isFullScreen = initParams->FullScreen; - - m_impl->_zoom = initParams->Zoom; - m_impl->_minWidth = initParams->MinWidth; - m_impl->_minHeight = initParams->MinHeight; - m_impl->_maxWidth = initParams->MaxWidth; - m_impl->_maxHeight = initParams->MaxHeight; - - m_impl->_webMessageReceivedCallback = initParams->WebMessageReceivedHandler; - m_impl->_resizedCallback = initParams->ResizedHandler; - m_impl->_movedCallback = initParams->MovedHandler; - m_impl->_closingCallback = initParams->ClosingHandler; - m_impl->_closedCallback = initParams->ClosedHandler; - m_impl->_focusInCallback = initParams->FocusInHandler; - m_impl->_focusOutCallback = initParams->FocusOutHandler; - m_impl->_maximizedCallback = initParams->MaximizedHandler; - m_impl->_minimizedCallback = initParams->MinimizedHandler; - m_impl->_restoredCallback = initParams->RestoredHandler; - m_impl->_customSchemeCallback = initParams->CustomSchemeHandler; - - for (int i = 0; i < 16; ++i) { - if (initParams->CustomSchemeNames[i] != nullptr) - m_impl->_customSchemeNames.emplace_back(initParams->CustomSchemeNames[i]); - } - - m_impl->_parent = initParams->ParentInstance; - - m_impl->_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - m_impl->_dialog = std::make_unique(); - - if (initParams->FullScreen) - SetFullScreen(true); - else { - if (initParams->Width > initParams->MaxWidth) - initParams->Width = initParams->MaxWidth; - if (initParams->Height > initParams->MaxHeight) - initParams->Height = initParams->MaxHeight; - if (initParams->Width < initParams->MinWidth) - initParams->Width = initParams->MinWidth; - if (initParams->Height < initParams->MinHeight) - initParams->Height = initParams->MinHeight; - - if (initParams->UseOsDefaultSize) - gtk_window_set_default_size(GTK_WINDOW(m_impl->_window), -1, -1); - else - gtk_window_set_default_size(GTK_WINDOW(m_impl->_window), initParams->Width, initParams->Height); - - SetMinSize(initParams->MinWidth, initParams->MinHeight); - SetMaxSize(initParams->MaxWidth, initParams->MaxHeight); - - if (initParams->UseOsDefaultLocation) - gtk_window_set_position(GTK_WINDOW(m_impl->_window), GTK_WIN_POS_NONE); - else if (initParams->CenterOnInitialize && !initParams->FullScreen) - gtk_window_set_position(GTK_WINDOW(m_impl->_window), GTK_WIN_POS_CENTER); - else - gtk_window_move(GTK_WINDOW(m_impl->_window), initParams->Left, initParams->Top); - } - - SetTitle(const_cast(m_impl->_windowTitle.c_str())); - - if (initParams->Chromeless) - gtk_window_set_decorated(GTK_WINDOW(m_impl->_window), false); - - if (initParams->WindowIconFile != nullptr && strlen(initParams->WindowIconFile) > 0) - SetIconFile(initParams->WindowIconFile); - - if (initParams->CenterOnInitialize) - Center(); - - if (initParams->Minimized) - SetMinimized(true); - - if (initParams->Maximized) - SetMaximized(true); - - if (!initParams->Resizable) - SetResizable(false); - - if (initParams->Topmost) - SetTopmost(true); - - g_signal_connect( - G_OBJECT(m_impl->_window), "configure-event", - G_CALLBACK(on_configure_event), this - ); - - g_signal_connect( - G_OBJECT(m_impl->_window), "window-state-event", - G_CALLBACK(on_window_state_event), this - ); - - g_signal_connect( - G_OBJECT(m_impl->_window), "delete-event", - G_CALLBACK(on_widget_deleted), this - ); - - g_signal_connect( - G_OBJECT(m_impl->_window), "destroy", - G_CALLBACK(on_widget_destroyed), this - ); - - // Register custom schemes before first navigation to avoid first-load races. - m_impl->AddCustomSchemeHandlers(); - - Show(false); - - g_signal_connect( - G_OBJECT(m_impl->_window), "focus-in-event", - G_CALLBACK(on_focus_in_event), this - ); - - g_signal_connect( - G_OBJECT(m_impl->_window), "focus-out-event", - G_CALLBACK(on_focus_out_event), this - ); - - g_signal_connect( - G_OBJECT(m_impl->_webview), "context-menu", - G_CALLBACK(on_webview_context_menu), this - ); - - g_signal_connect( - G_OBJECT(m_impl->_webview), "permission-request", - G_CALLBACK(on_permission_request), this - ); - - if (initParams->Transparent) - SetTransparentEnabled(true); - - if (m_impl->_zoom != 100.0) - SetZoom(m_impl->_zoom); -} - -InfiniFrameWindow::~InfiniFrameWindow() { - notify_uninit(); - gtk_widget_destroy(m_impl->_window); -} - -#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowCore.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowCore.Gtk.cpp new file mode 100644 index 000000000..665adbe30 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowCore.Gtk.cpp @@ -0,0 +1,49 @@ +#ifdef __linux__ + +#include +#include + +#include "Window.Gtk.Internal.h" + +InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) : + m_impl(std::make_unique()) { + XInitThreads(); + gtk_init(nullptr, nullptr); + notify_init(initParams->Title); + + if (initParams->Size != sizeof(InfiniFrameInitParams)) { + GtkWidget* dialog = gtk_message_dialog_new( + nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "Initial parameters passed are %i bytes, but expected %lu bytes.", + initParams->Size, sizeof(InfiniFrameInitParams) + ); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + exit(0); + } + + m_impl->InitializeFromParams(initParams); + m_impl->ConfigureInitialWindow(this, initParams); + m_impl->ApplyInitialWindowState(this, initParams); + m_impl->ConnectWindowSignals(this); + + // Register custom schemes before first navigation to avoid first-load races. + m_impl->AddCustomSchemeHandlers(); + + Show(false); + + m_impl->ConnectWebViewSignals(this); + + if (initParams->Transparent) + SetTransparentEnabled(true); + + if (m_impl->_zoom != 100.0) + SetZoom(m_impl->_zoom); +} + +InfiniFrameWindow::~InfiniFrameWindow() { + notify_uninit(); + gtk_widget_destroy(m_impl->_window); +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowInitialization.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowInitialization.Gtk.cpp new file mode 100644 index 000000000..1c164ee62 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowInitialization.Gtk.cpp @@ -0,0 +1,180 @@ +#ifdef __linux__ + +#include + +#include "Core/InfiniFrameDialog.h" +#include "Window.Gtk.Internal.h" + +gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, gpointer self); +gboolean on_window_state_event(GtkWidget* widget, GdkEventWindowState* event, gpointer self); +gboolean on_widget_deleted(GtkWidget* widget, GdkEvent* event, gpointer self); +void on_widget_destroyed(GtkWidget* widget, gpointer self); +gboolean on_focus_in_event(GtkWidget* widget, GdkEvent* event, gpointer self); +gboolean on_focus_out_event(GtkWidget* widget, GdkEvent* event, gpointer self); +gboolean on_webview_context_menu( + WebKitWebView* web_view, + GtkWidget* default_menu, + WebKitHitTestResult* hit_test_result, + gboolean triggered_with_keyboard, + gpointer user_data + ); +gboolean on_permission_request(WebKitWebView* web_view, WebKitPermissionRequest* request, gpointer user_data); + +void InfiniFrameWindow::Impl::InitializeFromParams(const InfiniFrameInitParams* initParams) { + _windowTitle = initParams->Title ? initParams->Title : ""; + + if (initParams->StartUrl != nullptr) + _startUrl = initParams->StartUrl; + if (initParams->StartString != nullptr) + _startString = initParams->StartString; + if (initParams->TemporaryFilesPath != nullptr) + _temporaryFilesPath = initParams->TemporaryFilesPath; + if (initParams->UserAgent != nullptr) + _userAgent = initParams->UserAgent; + if (initParams->BrowserControlInitParameters != nullptr) + _browserControlInitParameters = initParams->BrowserControlInitParameters; + + _transparentEnabled = initParams->Transparent; + _contextMenuEnabled = initParams->ContextMenuEnabled; + _zoomEnabled = initParams->ZoomEnabled; + _devToolsEnabled = initParams->DevToolsEnabled; + _grantBrowserPermissions = initParams->GrantBrowserPermissions; + _mediaAutoplayEnabled = initParams->MediaAutoplayEnabled; + _fileSystemAccessEnabled = initParams->FileSystemAccessEnabled; + _webSecurityEnabled = initParams->WebSecurityEnabled; + _javascriptClipboardAccessEnabled = initParams->JavascriptClipboardAccessEnabled; + _mediaStreamEnabled = initParams->MediaStreamEnabled; + _smoothScrollingEnabled = initParams->SmoothScrollingEnabled; + _ignoreCertificateErrorsEnabled = initParams->IgnoreCertificateErrorsEnabled; + _isFullScreen = initParams->FullScreen; + + _zoom = initParams->Zoom; + _minWidth = initParams->MinWidth; + _minHeight = initParams->MinHeight; + _maxWidth = initParams->MaxWidth; + _maxHeight = initParams->MaxHeight; + + _webMessageReceivedCallback = initParams->WebMessageReceivedHandler; + _resizedCallback = initParams->ResizedHandler; + _movedCallback = initParams->MovedHandler; + _closingCallback = initParams->ClosingHandler; + _closedCallback = initParams->ClosedHandler; + _focusInCallback = initParams->FocusInHandler; + _focusOutCallback = initParams->FocusOutHandler; + _maximizedCallback = initParams->MaximizedHandler; + _minimizedCallback = initParams->MinimizedHandler; + _restoredCallback = initParams->RestoredHandler; + _customSchemeCallback = initParams->CustomSchemeHandler; + + _customSchemeNames.clear(); + for (int i = 0; i < 16; ++i) { + if (initParams->CustomSchemeNames[i] != nullptr) + _customSchemeNames.emplace_back(initParams->CustomSchemeNames[i]); + } + + _parent = initParams->ParentInstance; +} + +void InfiniFrameWindow::Impl::ConfigureInitialWindow(InfiniFrameWindow* window, InfiniFrameInitParams* initParams) { + _window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + _dialog = std::make_unique(); + + if (initParams->FullScreen) { + window->SetFullScreen(true); + return; + } + + if (initParams->Width > initParams->MaxWidth) + initParams->Width = initParams->MaxWidth; + if (initParams->Height > initParams->MaxHeight) + initParams->Height = initParams->MaxHeight; + if (initParams->Width < initParams->MinWidth) + initParams->Width = initParams->MinWidth; + if (initParams->Height < initParams->MinHeight) + initParams->Height = initParams->MinHeight; + + if (initParams->UseOsDefaultSize) + gtk_window_set_default_size(GTK_WINDOW(_window), -1, -1); + else + gtk_window_set_default_size(GTK_WINDOW(_window), initParams->Width, initParams->Height); + + window->SetMinSize(initParams->MinWidth, initParams->MinHeight); + window->SetMaxSize(initParams->MaxWidth, initParams->MaxHeight); + + if (initParams->UseOsDefaultLocation) + gtk_window_set_position(GTK_WINDOW(_window), GTK_WIN_POS_NONE); + else if (initParams->CenterOnInitialize) + gtk_window_set_position(GTK_WINDOW(_window), GTK_WIN_POS_CENTER); + else + gtk_window_move(GTK_WINDOW(_window), initParams->Left, initParams->Top); +} + +void InfiniFrameWindow::Impl::ApplyInitialWindowState( + InfiniFrameWindow* window, + const InfiniFrameInitParams* initParams + ) { + window->SetTitle(const_cast(_windowTitle.c_str())); + + if (initParams->Chromeless) + gtk_window_set_decorated(GTK_WINDOW(_window), false); + + if (initParams->WindowIconFile != nullptr && std::strlen(initParams->WindowIconFile) > 0) + window->SetIconFile(initParams->WindowIconFile); + + if (initParams->CenterOnInitialize) + window->Center(); + if (initParams->Minimized) + window->SetMinimized(true); + if (initParams->Maximized) + window->SetMaximized(true); + if (!initParams->Resizable) + window->SetResizable(false); + if (initParams->Topmost) + window->SetTopmost(true); +} + +void InfiniFrameWindow::Impl::ConnectWindowSignals(InfiniFrameWindow* window) { + g_signal_connect( + G_OBJECT(_window), "configure-event", + G_CALLBACK(on_configure_event), window + ); + + g_signal_connect( + G_OBJECT(_window), "window-state-event", + G_CALLBACK(on_window_state_event), window + ); + + g_signal_connect( + G_OBJECT(_window), "delete-event", + G_CALLBACK(on_widget_deleted), window + ); + + g_signal_connect( + G_OBJECT(_window), "destroy", + G_CALLBACK(on_widget_destroyed), window + ); + + g_signal_connect( + G_OBJECT(_window), "focus-in-event", + G_CALLBACK(on_focus_in_event), window + ); + + g_signal_connect( + G_OBJECT(_window), "focus-out-event", + G_CALLBACK(on_focus_out_event), window + ); +} + +void InfiniFrameWindow::Impl::ConnectWebViewSignals(InfiniFrameWindow* window) { + g_signal_connect( + G_OBJECT(_webview), "context-menu", + G_CALLBACK(on_webview_context_menu), window + ); + + g_signal_connect( + G_OBJECT(_webview), "permission-request", + G_CALLBACK(on_permission_request), window + ); +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp index 3680da596..1f58dc3d9 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp @@ -2,6 +2,30 @@ #include "Window.Win32.Context.h" +void InfiniFrameWindow::WaitForExit() { + ApplyPendingOwnerWindow(m_impl.get(), L"wait_for_exit"); + + messageLoopRootWindowHandle = m_impl->_hWnd; + TraceTeardown(L"WaitForExit start instance=%p hwnd=%p", this, m_impl->_hWnd); + + MSG msg = {}; + while (true) { + const int getMessageResult = GetMessage(&msg, nullptr, 0, 0); + if (getMessageResult == -1) { + TraceTeardown(L"WaitForExit GetMessage failed err=%lu", GetLastError()); + break; + } + if (getMessageResult == 0) + break; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + messageLoopRootWindowHandle = nullptr; + TraceTeardown(L"WaitForExit end instance=%p hwnd=%p", this, m_impl->_hWnd); +} + void InfiniFrameWindow::Invoke(ACTION callback) { if (!callback) return; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Attach.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Attach.Win32.cpp new file mode 100644 index 000000000..67b1c5d5c --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Attach.Win32.cpp @@ -0,0 +1,578 @@ +#include +#include + +#include + +#include "Embedded/Embedded.h" +#include "Window.Win32.Context.h" + +using namespace Microsoft::WRL; + +void InfiniFrameWindow::Show(const bool isAlreadyShown) { + if (!isAlreadyShown) + ShowWindow(m_impl->_hWnd, SW_SHOWDEFAULT); + + UpdateWindow(m_impl->_hWnd); + + if (!m_impl->_webviewController) { + bool hasConfiguredRuntimePath = false; + { + std::lock_guard lock(webview2RuntimePathMutex); + hasConfiguredRuntimePath = wcsnlen(_webview2RuntimePath, _countof(_webview2RuntimePath)) > 0; + } + if (hasConfiguredRuntimePath || EnsureWebViewIsInstalled()) + AttachWebView(); + else + exit(0); + } +} + +void InfiniFrameWindow::AttachWebView() { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return; + + if (m_impl->_isWebView2Initializing || m_impl->_isInitialized) + return; + m_impl->_isWebView2Initializing = true; + + std::wstring configuredRuntimePath; + { + std::lock_guard lock(webview2RuntimePathMutex); + configuredRuntimePath = _webview2RuntimePath; + } + PCWSTR runtimePath = configuredRuntimePath.empty() ? nullptr : configuredRuntimePath.c_str(); + + std::wstring startupString; + if (!m_impl->_userAgent.empty()) + startupString += L"--user-agent=\"" + m_impl->_userAgent + L"\" "; + if (m_impl->_mediaAutoplayEnabled) + startupString += L"--autoplay-policy=no-user-gesture-required "; + if (m_impl->_fileSystemAccessEnabled) + startupString += L"--allow-file-access-from-files "; + if (!m_impl->_webSecurityEnabled) + startupString += L"--disable-web-security "; + if (m_impl->_javascriptClipboardAccessEnabled) + startupString += L"--enable-javascript-clipboard-access "; + if (m_impl->_mediaStreamEnabled) + startupString += L"--enable-usermedia-screen-capturing "; + if (!m_impl->_smoothScrollingEnabled) + startupString += L"--disable-smooth-scrolling "; + if (m_impl->_ignoreCertificateErrorsEnabled) + startupString += L"--ignore-certificate-errors "; + if (!m_impl->_browserControlInitParameters.empty()) + startupString += m_impl->_browserControlInitParameters; //e.g.--hide-scrollbars + + auto options = Microsoft::WRL::Make(); + if (startupString.length() > 0) + options->put_AdditionalBrowserArguments(startupString.c_str()); + + bool requiresAppSchemeRegistration = std::any_of( + m_impl->_customSchemeNames.begin(), + m_impl->_customSchemeNames.end(), + [](const std::wstring& schemeName) { + return _wcsicmp(schemeName.c_str(), L"app") == 0; + } + ); + bool appSchemeRegistrationSupported = false; + + // Register custom schemes with WebView2 so top-level navigations like app://... are allowed. + if (!m_impl->_customSchemeNames.empty()) { + wil::com_ptr options4; + if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&options4))) && options4) { + appSchemeRegistrationSupported = true; + std::vector> registrations; + registrations.reserve(m_impl->_customSchemeNames.size()); + + for (const auto& schemeName : m_impl->_customSchemeNames) { + auto registration = Microsoft::WRL::Make(schemeName.c_str()); + if (!registration) + continue; + + // Only the embedded-assets scheme uses app://localhost/... and should be + // treated as secure with an authority component. + if (_wcsicmp(schemeName.c_str(), L"app") == 0) { + registration->put_HasAuthorityComponent(TRUE); + registration->put_TreatAsSecure(TRUE); + } + registrations.emplace_back(registration); + } + + if (!registrations.empty()) { + std::vector rawRegistrations; + rawRegistrations.reserve(registrations.size()); + for (auto& registration : registrations) + rawRegistrations.emplace_back(registration.get()); + + options4->SetCustomSchemeRegistrations( + static_cast(rawRegistrations.size()), + rawRegistrations.data() + ); + } + } + } + + if (requiresAppSchemeRegistration && !appSchemeRegistrationSupported) { + MessageBox( + m_impl->_hWnd, + L"This app requires WebView2 custom scheme registration for app://localhost/. Please update WebView2 Runtime to a version that supports ICoreWebView2EnvironmentOptions4.", + L"WebView2 Runtime Too Old", + MB_OK | MB_ICONERROR + ); + m_impl->_isWebView2Initializing = false; + return; + } + + PCWSTR userDataPath = nullptr; + if (!m_impl->_temporaryFilesPath.empty()) { + if (EnsureDirectoryWritable(m_impl->_temporaryFilesPath)) + userDataPath = m_impl->_temporaryFilesPath.c_str(); + else + TraceTeardown( + L"AttachWebView: temporary user-data path is not writable. Falling back to default path. path=%ls", + m_impl->_temporaryFilesPath.c_str() + ); + } + + HRESULT envResult = CreateCoreWebView2EnvironmentWithOptions( + runtimePath, + userDataPath, + options.Get(), + Callback< + ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>( + [this]( + const HRESULT result, + ICoreWebView2Environment* env + ) -> HRESULT { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { + m_impl->_isWebView2Initializing = false; + m_impl->_webviewEnvironment = nullptr; + TraceTeardown(L"CreateEnvironment callback while closing; ignoring"); + return S_OK; + } + if (result != S_OK) { + m_impl->_isWebView2Initializing = false; + TraceTeardown(L"CreateEnvironment callback failed hr=0x%08X", static_cast(result)); + return result; + } + if (env == nullptr) { + m_impl->_isWebView2Initializing = false; + return E_POINTER; + } + HRESULT envResult = env->QueryInterface( + &m_impl->_webviewEnvironment + ); + if (envResult != S_OK) { + m_impl->_isWebView2Initializing = false; + return envResult; + } + + const HRESULT createControllerHr = env->CreateCoreWebView2Controller( + m_impl->_hWnd, + Callback< + ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>( + [this]( + const HRESULT result, + ICoreWebView2Controller* controller + ) -> + HRESULT { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { + if (controller != nullptr) + controller->Close(); + m_impl->_webviewController = nullptr; + m_impl->_webviewWindow = nullptr; + m_impl->_webviewEnvironment = nullptr; + m_impl->_isWebView2Initializing = false; + TraceTeardown(L"CreateController callback while closing; ignoring"); + return S_OK; + } + if (result != S_OK) { + m_impl->_isWebView2Initializing = false; + TraceTeardown( + L"CreateController callback failed hr=0x%08X", + static_cast(result) + ); + return result; + } + if (controller == nullptr) { + m_impl->_isWebView2Initializing = false; + return E_POINTER; + } + + HRESULT envResult = controller->QueryInterface(&m_impl->_webviewController); + if (envResult != S_OK) { + m_impl->_isWebView2Initializing = false; + return envResult; + } + m_impl->_webviewController->get_CoreWebView2(&m_impl->_webviewWindow); + if (!m_impl->_webviewWindow) { + m_impl->_isWebView2Initializing = false; + return E_FAIL; + } + + const auto js_wide = Embedded::InfiniFrameJsUtf16(); + OutputDebugStringW( + std::format(L"[InfiniFrame] Bridge script length: {} chars\n", js_wide.size()). + c_str() + ); + + struct NavigateOnce { + InfiniFrameWindow* self; + bool fired = false; + void navigate() { + if (fired) + return; + fired = true; + if (!self->m_impl->_startUrl.empty()) + self->m_impl->_webviewWindow->Navigate(self->m_impl->_startUrl.c_str()); + else if (!self->m_impl->_startString.empty()) + self->m_impl->_webviewWindow->NavigateToString( + self->m_impl->_startString.c_str() + ); + else { + MessageBox( + nullptr, + L"Neither StartUrl nor StartString was specified", + L"Native Initialization Failed", + MB_OK + ); + exit(0); + } + } + }; + auto nav = std::make_shared(NavigateOnce{this}); + + wil::com_ptr settings; + HRESULT settingsResult = m_impl->_webviewWindow->get_Settings(&settings); + if (FAILED(settingsResult) || !settings) { + return FAILED(settingsResult) + ? settingsResult + : E_FAIL; + } + settings->put_AreHostObjectsAllowed(TRUE); + settings->put_IsScriptEnabled(TRUE); + settings->put_AreDefaultScriptDialogsEnabled(TRUE); + settings->put_IsWebMessageEnabled(TRUE); + + EventRegistrationToken webMessageToken; + m_impl->_webviewWindow->add_WebMessageReceived( + Callback< + ICoreWebView2WebMessageReceivedEventHandler>( + [this]( + ICoreWebView2*, + ICoreWebView2WebMessageReceivedEventArgs + * args + ) -> HRESULT { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return S_OK; + + wil::unique_cotaskmem_string message; + wil::unique_cotaskmem_string source; + args->TryGetWebMessageAsString(&message); + args->get_Source(&source); + if ( + (source.get() == nullptr || source.get()[0] == L'\0') + && m_impl->_webviewWindow != nullptr + ) { + m_impl->_webviewWindow->get_Source(&source); + } + m_impl->_webMessageReceivedCallback( + message.get(), + source.get() + ); + return S_OK; + } + ).Get(), + &webMessageToken + ); + m_impl->_webMessageReceivedToken = webMessageToken; + m_impl->_hasWebMessageReceivedToken = true; + + EventRegistrationToken webResourceRequestedToken; + auto webview23 = m_impl->_webviewWindow.try_query(); + if (webview23) { + webview23->AddWebResourceRequestedFilterWithRequestSourceKinds( + L"*", + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL + ); + } + else { + m_impl->_webviewWindow->AddWebResourceRequestedFilter( + L"*", + COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL + ); + } + m_impl->_webviewWindow->add_WebResourceRequested( + Callback< + ICoreWebView2WebResourceRequestedEventHandler>( + [this]( + ICoreWebView2*, + ICoreWebView2WebResourceRequestedEventArgs + * args + ) { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return S_OK; + + wil::com_ptr< + ICoreWebView2WebResourceRequest> req; + if (FAILED(args->get_Request(&req)) || !req) + return S_OK; + + wil::unique_cotaskmem_string uri; + req->get_Uri(&uri); + std::wstring uriString = uri.get(); + wil::com_ptr requestHeaders; + std::wstring requestOrigin; + if (SUCCEEDED(req->get_Headers(&requestHeaders)) && requestHeaders) { + wil::unique_cotaskmem_string originHeaderValue; + if (SUCCEEDED( + requestHeaders->GetHeader(L"Origin", &originHeaderValue) + ) + && originHeaderValue.get() != nullptr + && originHeaderValue.get()[0] != L'\0') { + requestOrigin = originHeaderValue.get(); + } + } + + if (uriString.find(L"/_framework/blazor.modules.json") != + std::wstring::npos) { + static constexpr BYTE emptyModuleArray[] = {'[', ']'}; + wil::com_ptr dataStream; + dataStream.attach( + SHCreateMemStream(emptyModuleArray, sizeof(emptyModuleArray)) + ); + if (!dataStream) + return S_OK; + + std::wstring responseHeaders = L"Content-Type: application/json"; + responseHeaders += + L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; + responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; + if (!requestOrigin.empty()) { + responseHeaders += L"\r\nAccess-Control-Allow-Origin: " + + requestOrigin; + responseHeaders += + L"\r\nAccess-Control-Allow-Credentials: true"; + responseHeaders += L"\r\nVary: Origin"; + } + else { + responseHeaders += L"\r\nAccess-Control-Allow-Origin: *"; + } + + wil::com_ptr response; + m_impl->_webviewEnvironment->CreateWebResourceResponse( + dataStream.get(), + 200, + L"OK", + responseHeaders.c_str(), + &response + ); + args->put_Response(response.get()); + return S_OK; + } + size_t colonPos = uriString.find(L':', 0); + if (colonPos > 0) { + std::wstring scheme = uriString.substr(0, colonPos); + auto it = std::find( + m_impl + -> + _customSchemeNames + .begin(), + m_impl + -> + _customSchemeNames + .end(), + scheme + ); + + if (it != + m_impl-> + _customSchemeNames + .end() && + m_impl-> + _customSchemeCallback + != + nullptr) { + int numBytes; + AutoString contentType = nullptr; + wil::unique_cotaskmem dotNetResponse( + m_impl + -> + _customSchemeCallback( + const_cast + + (uriString + .c_str()), + &numBytes, + &contentType + ) + ); + auto freeContentType = wil::scope_exit( + [& + contentType + ] { + CoTaskMemFree( + contentType + ); + } + ); + + if ( + dotNetResponse + != + nullptr + && + contentType + != + nullptr) { + std::wstring contentTypeWS = contentType; + + wil::com_ptr dataStream; + dataStream.attach( + SHCreateMemStream( + reinterpret_cast + + (dotNetResponse + .get()), + numBytes + ) + ); + if (! + dataStream) + return + S_OK; + wil::com_ptr + + response; + std::wstring responseHeaders = L"Content-Type: " + + contentTypeWS; + responseHeaders += + L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; + responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; + if (!requestOrigin.empty()) { + responseHeaders += L"\r\nAccess-Control-Allow-Origin: " + + requestOrigin; + responseHeaders += + L"\r\nAccess-Control-Allow-Credentials: true"; + responseHeaders += L"\r\nVary: Origin"; + } + else { + responseHeaders += + L"\r\nAccess-Control-Allow-Origin: *"; + } + m_impl + -> + _webviewEnvironment + -> + CreateWebResourceResponse( + dataStream + .get(), + 200, + L"OK", + responseHeaders.c_str(), + &response + ); + args-> + put_Response( + response + .get() + ); + } + } + } + + return S_OK; + } + ).Get(), + &webResourceRequestedToken + ); + m_impl->_webResourceRequestedTokenForCustomScheme = webResourceRequestedToken; + m_impl->_hasWebResourceRequestedToken = true; + + EventRegistrationToken permissionRequestedToken; + m_impl->_webviewWindow->add_PermissionRequested( + Callback< + ICoreWebView2PermissionRequestedEventHandler>( + [this]( + ICoreWebView2*, + ICoreWebView2PermissionRequestedEventArgs + * args + ) -> HRESULT { + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return S_OK; + + if (m_impl->_grantBrowserPermissions) + args->put_State( + COREWEBVIEW2_PERMISSION_STATE_ALLOW + ); + return S_OK; + } + ) + .Get(), + &permissionRequestedToken + ); + m_impl->_permissionRequestedToken = permissionRequestedToken; + m_impl->_hasPermissionRequestedToken = true; + + if (!m_impl->_contextMenuEnabled) + SetContextMenuEnabled(false); + if (!m_impl->_zoomEnabled) + SetZoomEnabled(false); + if (!m_impl->_devToolsEnabled) + SetDevToolsEnabled(false); + if (m_impl->_transparentEnabled) + SetTransparentEnabled(true); + if (m_impl->_zoom != 100) + SetZoom(m_impl->_zoom); + + HRESULT addScriptHr = m_impl->_webviewWindow->AddScriptToExecuteOnDocumentCreated( + js_wide.c_str(), + Callback( + [nav, this](HRESULT errorCode, LPCWSTR id) -> HRESULT { + OutputDebugStringW( + std::format( + L"[InfiniFrame] AddScriptToExecuteOnDocumentCreated callback: hr=0x{:08X} id={}\n", + (unsigned)errorCode, + id ? id : L"(null)" + ).c_str() + ); + if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) + return S_OK; + nav->navigate(); + return S_OK; + } + ).Get() + ); + + if (FAILED(addScriptHr)) + nav->navigate(); + + RefitContent(); + FocusWebView2(); + + if (m_impl->_topmost) + SetTopmost(true); + + m_impl->_isInitialized = true; + m_impl->_isWebView2Initializing = false; + return S_OK; + } + ).Get() + ); + if (FAILED(createControllerHr)) + m_impl->_isWebView2Initializing = false; + + return createControllerHr; + } + ).Get() + ); + + if (envResult != S_OK) { + m_impl->_isWebView2Initializing = false; + _com_error err(envResult); + LPCTSTR errMsg = err.ErrorMessage(); + MessageBox(m_impl->_hWnd, errMsg, L"Error instantiating webview", MB_OK); + } +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Controller.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Controller.Win32.cpp new file mode 100644 index 000000000..f9250f692 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Controller.Win32.cpp @@ -0,0 +1,57 @@ +#include "Window.Win32.Context.h" + +using namespace Microsoft::WRL; + +void InfiniFrameWindow::RefitContent() { + if (m_impl->_webviewController) { + RECT bounds; + GetClientRect(m_impl->_hWnd, &bounds); + m_impl->_webviewController->put_Bounds(bounds); + } +} + +void InfiniFrameWindow::FocusWebView2() { + if (m_impl->_webviewController) { + m_impl->_webviewController->MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC); + } +} + +void InfiniFrameWindow::NotifyWebView2WindowMove() { + if (m_impl->_webviewController) { + m_impl->_webviewController->NotifyParentWindowPositionChanged(); + } +} + +void InfiniFrameWindow::ClearBrowserAutoFill() { + if (!m_impl->_webviewWindow) + return; + + auto webview15 = m_impl->_webviewWindow.try_query(); + if (webview15) { + wil::com_ptr profile; + webview15->get_Profile(&profile); + auto profile2 = profile.try_query(); + + if (profile2) { + COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds = + (COREWEBVIEW2_BROWSING_DATA_KINDS) + ( + COREWEBVIEW2_BROWSING_DATA_KINDS_GENERAL_AUTOFILL | + COREWEBVIEW2_BROWSING_DATA_KINDS_PASSWORD_AUTOSAVE + ); + + profile2->ClearBrowsingData( + dataKinds, + Callback( + [this]( + HRESULT + ) + -> HRESULT { + return S_OK; + } + ) + .Get() + ); + } + } +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp index 10381ba3c..59b2633cc 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp @@ -1,11 +1,4 @@ -#include -#include -#include - #include "Window.Win32.Context.h" -#include "Embedded/Embedded.h" - -using namespace Microsoft::WRL; void InfiniFrameWindow::CloseWebView() { m_impl->_isClosingOrClosed.store(true, std::memory_order_release); @@ -60,767 +53,3 @@ std::string InfiniFrameWindow::ToUTF8String(const AutoString source) const { std::wstring InfiniFrameWindow::ToUTF16String(const AutoString source) const { return Utf8ToWide(source); } - -bool InfiniFrameWindow::EnsureWebViewIsInstalled() { - LPWSTR versionInfo = nullptr; - HRESULT ensureInstalledResult = GetAvailableCoreWebView2BrowserVersionString(nullptr, &versionInfo); - if (versionInfo != nullptr) - CoTaskMemFree(versionInfo); - - if (ensureInstalledResult != S_OK) - return InstallWebView2(); - - return true; -} - -bool InfiniFrameWindow::InstallWebView2() { - auto srcURL = L"https://go.microsoft.com/fwlink/p/?LinkId=2124703"; - auto destFile = L"MicrosoftEdgeWebview2Setup.exe"; - - if (S_OK == URLDownloadToFile(nullptr, srcURL, destFile, 0, nullptr)) { - std::wstring command = L"MicrosoftEdgeWebview2Setup.exe"; - - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - bool success = CreateProcess( - nullptr, - command.data(), - nullptr, - nullptr, - FALSE, - 0, - nullptr, - nullptr, - &si, - &pi - ); - - if (success) { - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - - return success; - } - - return false; -} - -void InfiniFrameWindow::RefitContent() { - if (m_impl->_webviewController) { - RECT bounds; - GetClientRect(m_impl->_hWnd, &bounds); - m_impl->_webviewController->put_Bounds(bounds); - } -} - -void InfiniFrameWindow::FocusWebView2() { - if (m_impl->_webviewController) { - m_impl->_webviewController->MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC); - } -} - -void InfiniFrameWindow::NotifyWebView2WindowMove() { - if (m_impl->_webviewController) { - m_impl->_webviewController->NotifyParentWindowPositionChanged(); - } -} - -void InfiniFrameWindow::ClearBrowserAutoFill() { - if (!m_impl->_webviewWindow) - return; - - auto webview15 = m_impl->_webviewWindow.try_query(); - if (webview15) { - wil::com_ptr profile; - webview15->get_Profile(&profile); - auto profile2 = profile.try_query(); - - if (profile2) { - COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds = - (COREWEBVIEW2_BROWSING_DATA_KINDS) - ( - COREWEBVIEW2_BROWSING_DATA_KINDS_GENERAL_AUTOFILL | - COREWEBVIEW2_BROWSING_DATA_KINDS_PASSWORD_AUTOSAVE - ); - - profile2->ClearBrowsingData( - dataKinds, - Callback( - [this]( - HRESULT - ) - -> HRESULT { - return S_OK; - } - ) - .Get() - ); - } - } -} - -void InfiniFrameWindow::SetWebView2RuntimePath(const AutoString pathToWebView2) { - if (pathToWebView2 == nullptr) - return; - - std::wstring widePath = Utf8ToWide(pathToWebView2); - std::lock_guard lock(webview2RuntimePathMutex); - wcsncpy_s(_webview2RuntimePath, widePath.c_str(), _countof(_webview2RuntimePath)); -} - -void InfiniFrameWindow::Show(const bool isAlreadyShown) { - if (!isAlreadyShown) - ShowWindow(m_impl->_hWnd, SW_SHOWDEFAULT); - - UpdateWindow(m_impl->_hWnd); - - if (!m_impl->_webviewController) { - bool hasConfiguredRuntimePath = false; - { - std::lock_guard lock(webview2RuntimePathMutex); - hasConfiguredRuntimePath = wcsnlen(_webview2RuntimePath, _countof(_webview2RuntimePath)) > 0; - } - if (hasConfiguredRuntimePath || EnsureWebViewIsInstalled()) - AttachWebView(); - else - exit(0); - } -} - -void InfiniFrameWindow::AttachWebView() { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return; - - if (m_impl->_isWebView2Initializing || m_impl->_isInitialized) - return; - m_impl->_isWebView2Initializing = true; - - std::wstring configuredRuntimePath; - { - std::lock_guard lock(webview2RuntimePathMutex); - configuredRuntimePath = _webview2RuntimePath; - } - PCWSTR runtimePath = configuredRuntimePath.empty() ? nullptr : configuredRuntimePath.c_str(); - - std::wstring startupString; - if (!m_impl->_userAgent.empty()) - startupString += L"--user-agent=\"" + m_impl->_userAgent + L"\" "; - if (m_impl->_mediaAutoplayEnabled) - startupString += L"--autoplay-policy=no-user-gesture-required "; - if (m_impl->_fileSystemAccessEnabled) - startupString += L"--allow-file-access-from-files "; - if (!m_impl->_webSecurityEnabled) - startupString += L"--disable-web-security "; - if (m_impl->_javascriptClipboardAccessEnabled) - startupString += L"--enable-javascript-clipboard-access "; - if (m_impl->_mediaStreamEnabled) - startupString += L"--enable-usermedia-screen-capturing "; - if (!m_impl->_smoothScrollingEnabled) - startupString += L"--disable-smooth-scrolling "; - if (m_impl->_ignoreCertificateErrorsEnabled) - startupString += L"--ignore-certificate-errors "; - if (!m_impl->_browserControlInitParameters.empty()) - startupString += m_impl->_browserControlInitParameters; //e.g.--hide-scrollbars - - auto options = Microsoft::WRL::Make(); - if (startupString.length() > 0) - options->put_AdditionalBrowserArguments(startupString.c_str()); - - bool requiresAppSchemeRegistration = std::any_of( - m_impl->_customSchemeNames.begin(), - m_impl->_customSchemeNames.end(), - [](const std::wstring& schemeName) { - return _wcsicmp(schemeName.c_str(), L"app") == 0; - } - ); - bool appSchemeRegistrationSupported = false; - - // Register custom schemes with WebView2 so top-level navigations like app://... are allowed. - if (!m_impl->_customSchemeNames.empty()) { - wil::com_ptr options4; - if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&options4))) && options4) { - appSchemeRegistrationSupported = true; - std::vector> registrations; - registrations.reserve(m_impl->_customSchemeNames.size()); - - for (const auto& schemeName : m_impl->_customSchemeNames) { - auto registration = Microsoft::WRL::Make(schemeName.c_str()); - if (!registration) - continue; - - // Only the embedded-assets scheme uses app://localhost/... and should be - // treated as secure with an authority component. - if (_wcsicmp(schemeName.c_str(), L"app") == 0) { - registration->put_HasAuthorityComponent(TRUE); - registration->put_TreatAsSecure(TRUE); - } - registrations.emplace_back(registration); - } - - if (!registrations.empty()) { - std::vector rawRegistrations; - rawRegistrations.reserve(registrations.size()); - for (auto& registration : registrations) - rawRegistrations.emplace_back(registration.get()); - - options4->SetCustomSchemeRegistrations( - static_cast(rawRegistrations.size()), - rawRegistrations.data() - ); - } - } - } - - if (requiresAppSchemeRegistration && !appSchemeRegistrationSupported) { - MessageBox( - m_impl->_hWnd, - L"This app requires WebView2 custom scheme registration for app://localhost/. Please update WebView2 Runtime to a version that supports ICoreWebView2EnvironmentOptions4.", - L"WebView2 Runtime Too Old", - MB_OK | MB_ICONERROR - ); - m_impl->_isWebView2Initializing = false; - return; - } - - PCWSTR userDataPath = nullptr; - if (!m_impl->_temporaryFilesPath.empty()) { - if (EnsureDirectoryWritable(m_impl->_temporaryFilesPath)) - userDataPath = m_impl->_temporaryFilesPath.c_str(); - else - TraceTeardown( - L"AttachWebView: temporary user-data path is not writable. Falling back to default path. path=%ls", - m_impl->_temporaryFilesPath.c_str() - ); - } - - HRESULT envResult = CreateCoreWebView2EnvironmentWithOptions( - runtimePath, - userDataPath, - options.Get(), - Callback< - ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>( - [this]( - const HRESULT result, - ICoreWebView2Environment* env - ) -> HRESULT { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { - m_impl->_isWebView2Initializing = false; - m_impl->_webviewEnvironment = nullptr; - TraceTeardown(L"CreateEnvironment callback while closing; ignoring"); - return S_OK; - } - if (result != S_OK) { - m_impl->_isWebView2Initializing = false; - TraceTeardown(L"CreateEnvironment callback failed hr=0x%08X", static_cast(result)); - return result; - } - if (env == nullptr) { - m_impl->_isWebView2Initializing = false; - return E_POINTER; - } - HRESULT envResult = env->QueryInterface( - &m_impl->_webviewEnvironment - ); - if (envResult != S_OK) { - m_impl->_isWebView2Initializing = false; - return envResult; - } - - const HRESULT createControllerHr = env->CreateCoreWebView2Controller( - m_impl->_hWnd, - Callback< - ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>( - [this]( - const HRESULT result, - ICoreWebView2Controller* controller - ) -> - HRESULT { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { - if (controller != nullptr) - controller->Close(); - m_impl->_webviewController = nullptr; - m_impl->_webviewWindow = nullptr; - m_impl->_webviewEnvironment = nullptr; - m_impl->_isWebView2Initializing = false; - TraceTeardown(L"CreateController callback while closing; ignoring"); - return S_OK; - } - if (result != S_OK) { - m_impl->_isWebView2Initializing = false; - TraceTeardown(L"CreateController callback failed hr=0x%08X", static_cast(result)); - return result; - } - if (controller == nullptr) { - m_impl->_isWebView2Initializing = false; - return E_POINTER; - } - - HRESULT envResult = controller-> - QueryInterface( - &m_impl-> - _webviewController - ); - if (envResult != S_OK) { - m_impl->_isWebView2Initializing = false; - return envResult; - } - m_impl->_webviewController->get_CoreWebView2(&m_impl->_webviewWindow); - if (!m_impl->_webviewWindow) { - m_impl->_isWebView2Initializing = false; - return E_FAIL; - } - - const auto js_wide = Embedded::InfiniFrameJsUtf16(); - OutputDebugStringW(std::format(L"[InfiniFrame] Bridge script length: {} chars\n", js_wide.size()).c_str()); - - // AddScriptToExecuteOnDocumentCreated is async: the script is not - // registered in the browser process until the completion callback fires. - // We must not navigate until then, otherwise fast local navigations - // (e.g., app://localhost/) reach ContentLoading before the bridge script - // exists, and Blazor's Boot.WebView.ts throws because - // window.external.receiveMessage is undefined. - // - // If script registration fails for any reason (e.g., empty resource), - // we fall through and navigate anyway so the page still loads. - struct NavigateOnce { - InfiniFrameWindow* self; - bool fired = false; - void navigate() { - if (fired) return; - fired = true; - if (!self->m_impl->_startUrl.empty()) - self->m_impl->_webviewWindow->Navigate(self->m_impl->_startUrl.c_str()); - else if (!self->m_impl->_startString.empty()) - self->m_impl->_webviewWindow->NavigateToString(self->m_impl->_startString.c_str()); - else { - MessageBox(nullptr, - L"Neither StartUrl nor StartString was specified", - L"Native Initialization Failed", MB_OK); - exit(0); - } - } - }; - auto nav = std::make_shared(NavigateOnce{this}); - - wil::com_ptr - settings; - HRESULT settingsResult = m_impl-> - _webviewWindow->get_Settings( - &settings - ); - if (FAILED(settingsResult) || ! - settings) { - return FAILED(settingsResult) - ? settingsResult - : E_FAIL; - } - settings-> - put_AreHostObjectsAllowed( - TRUE - ); - settings->put_IsScriptEnabled( - TRUE - ); - settings-> - put_AreDefaultScriptDialogsEnabled( - TRUE - ); - settings->put_IsWebMessageEnabled( - TRUE - ); - - EventRegistrationToken - webMessageToken; - - m_impl->_webviewWindow-> - add_WebMessageReceived( - Callback< - ICoreWebView2WebMessageReceivedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2WebMessageReceivedEventArgs - * args - ) -> HRESULT { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return S_OK; - - wil::unique_cotaskmem_string - message; - wil::unique_cotaskmem_string - source; - args-> - TryGetWebMessageAsString( - &message - ); - args-> - get_Source( - &source - ); - if ( - (source.get() == nullptr - || source.get()[0] == L'\0') - && m_impl->_webviewWindow != nullptr - ) { - m_impl-> - _webviewWindow-> - get_Source( - &source - ); - } - m_impl-> - _webMessageReceivedCallback( - message. - get(), - source. - get() - ); - return S_OK; - } - ).Get(), - &webMessageToken - ); - m_impl->_webMessageReceivedToken = webMessageToken; - m_impl->_hasWebMessageReceivedToken = true; - - EventRegistrationToken - webResourceRequestedToken; - auto webview23 = m_impl->_webviewWindow.try_query(); - if (webview23) { - webview23->AddWebResourceRequestedFilterWithRequestSourceKinds( - L"*", - COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, - COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL - ); - } - else { - m_impl->_webviewWindow-> - AddWebResourceRequestedFilter( - L"*", - COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL - ); - } - m_impl->_webviewWindow-> - add_WebResourceRequested( - Callback< - ICoreWebView2WebResourceRequestedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2WebResourceRequestedEventArgs - * args - ) { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return S_OK; - - wil::com_ptr< - ICoreWebView2WebResourceRequest> - req; - if (FAILED( - args-> - get_Request( - &req - ) - ) - || ! - req) - return S_OK; - - wil::unique_cotaskmem_string - uri; - req->get_Uri(&uri); - std::wstring - uriString = uri - .get(); - wil::com_ptr - requestHeaders; - std::wstring requestOrigin; - if (SUCCEEDED(req->get_Headers(&requestHeaders)) && requestHeaders) { - wil::unique_cotaskmem_string originHeaderValue; - if (SUCCEEDED( - requestHeaders->GetHeader(L"Origin", &originHeaderValue) - ) - && originHeaderValue.get() != nullptr - && originHeaderValue.get()[0] != L'\0') { - requestOrigin = originHeaderValue.get(); - } - } - - if (uriString.find(L"/_framework/blazor.modules.json") != - std::wstring::npos) { - static constexpr BYTE emptyModuleArray[] = {'[', ']'}; - wil::com_ptr dataStream; - dataStream.attach( - SHCreateMemStream(emptyModuleArray, sizeof(emptyModuleArray)) - ); - if (!dataStream) - return S_OK; - - std::wstring responseHeaders = L"Content-Type: application/json"; - responseHeaders += - L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; - responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; - if (!requestOrigin.empty()) { - responseHeaders += L"\r\nAccess-Control-Allow-Origin: " + - requestOrigin; - responseHeaders += - L"\r\nAccess-Control-Allow-Credentials: true"; - responseHeaders += L"\r\nVary: Origin"; - } - else { - responseHeaders += L"\r\nAccess-Control-Allow-Origin: *"; - } - - wil::com_ptr response; - m_impl->_webviewEnvironment->CreateWebResourceResponse( - dataStream.get(), - 200, - L"OK", - responseHeaders.c_str(), - &response - ); - args->put_Response(response.get()); - return S_OK; - } - size_t colonPos = - uriString.find( - L':', 0 - ); - if (colonPos > 0) { - std::wstring - scheme = - uriString - .substr( - 0, - colonPos - ); - auto it = - std::find( - m_impl - -> - _customSchemeNames - .begin(), - m_impl - -> - _customSchemeNames - .end(), - scheme - ); - - if (it != - m_impl-> - _customSchemeNames - .end() && - m_impl-> - _customSchemeCallback - != - nullptr) { - int - numBytes; - AutoString - contentType - = nullptr; - wil::unique_cotaskmem - dotNetResponse( - m_impl - -> - _customSchemeCallback( - const_cast - - (uriString - .c_str()), - &numBytes, - &contentType - ) - ); - auto - freeContentType - = wil::scope_exit( - [& - contentType - ] { - CoTaskMemFree( - contentType - ); - } - ); - - if ( - dotNetResponse - != - nullptr - && - contentType - != - nullptr) { - std::wstring - contentTypeWS - = contentType; - - wil::com_ptr - - dataStream; - dataStream - .attach( - SHCreateMemStream( - reinterpret_cast - - (dotNetResponse - .get()), - numBytes - ) - ); - if (! - dataStream) - return - S_OK; - wil::com_ptr - - response; - std::wstring responseHeaders = L"Content-Type: " + - contentTypeWS; - responseHeaders += - L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; - responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; - if (!requestOrigin.empty()) { - responseHeaders += L"\r\nAccess-Control-Allow-Origin: " - + requestOrigin; - responseHeaders += - L"\r\nAccess-Control-Allow-Credentials: true"; - responseHeaders += L"\r\nVary: Origin"; - } - else { - responseHeaders += - L"\r\nAccess-Control-Allow-Origin: *"; - } - m_impl - -> - _webviewEnvironment - -> - CreateWebResourceResponse( - dataStream - .get(), - 200, - L"OK", - responseHeaders.c_str(), - &response - ); - args-> - put_Response( - response - .get() - ); - } - } - } - - return S_OK; - } - ).Get(), - &webResourceRequestedToken - ); - m_impl->_webResourceRequestedTokenForCustomScheme = webResourceRequestedToken; - m_impl->_hasWebResourceRequestedToken = true; - - EventRegistrationToken - permissionRequestedToken; - m_impl->_webviewWindow-> - add_PermissionRequested( - Callback< - ICoreWebView2PermissionRequestedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2PermissionRequestedEventArgs - * args - ) -> HRESULT { - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return S_OK; - - if (m_impl-> - _grantBrowserPermissions) - args-> - put_State( - COREWEBVIEW2_PERMISSION_STATE_ALLOW - ); - return S_OK; - } - ) - .Get(), - &permissionRequestedToken - ); - m_impl->_permissionRequestedToken = permissionRequestedToken; - m_impl->_hasPermissionRequestedToken = true; - - if (m_impl->_contextMenuEnabled == - false) - SetContextMenuEnabled(false); - - if (m_impl->_zoomEnabled == false) - SetZoomEnabled(false); - - if (m_impl->_devToolsEnabled == - false) - SetDevToolsEnabled(false); - - if (m_impl->_transparentEnabled == - true) - SetTransparentEnabled(true); - - if (m_impl->_zoom != 100) - SetZoom(m_impl->_zoom); - - HRESULT addScriptHr = m_impl->_webviewWindow->AddScriptToExecuteOnDocumentCreated( - js_wide.c_str(), - Callback( - [nav, this](HRESULT errorCode, LPCWSTR id) -> HRESULT { - OutputDebugStringW(std::format(L"[InfiniFrame] AddScriptToExecuteOnDocumentCreated callback: hr=0x{:08X} id={}\n", (unsigned)errorCode, id ? id : L"(null)").c_str()); - if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) - return S_OK; - nav->navigate(); - return S_OK; - } - ).Get() - ); - - // If AddScriptToExecuteOnDocumentCreated itself failed synchronously - // (e.g., empty script string on some WebView2 versions), navigate now - // so the page is not left blank. - if (FAILED(addScriptHr)) - nav->navigate(); - - RefitContent(); - - FocusWebView2(); - - // Re-apply if topmost was requested - if (m_impl->_topmost) - SetTopmost(true); - - m_impl->_isInitialized = true; - m_impl->_isWebView2Initializing = false; - return S_OK; - } - ).Get() - ); - if (FAILED(createControllerHr)) - m_impl->_isWebView2Initializing = false; - - return createControllerHr; - } - ).Get() - ); - - if (envResult != S_OK) { - m_impl->_isWebView2Initializing = false; - _com_error err(envResult); - LPCTSTR errMsg = err.ErrorMessage(); - MessageBox(m_impl->_hWnd, errMsg, L"Error instantiating webview", MB_OK); - } -} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Runtime.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Runtime.Win32.cpp new file mode 100644 index 000000000..c32bc5acc --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Runtime.Win32.cpp @@ -0,0 +1,65 @@ +#include + +#include "Window.Win32.Context.h" + +#pragma comment(lib, "Urlmon.lib") + +bool InfiniFrameWindow::EnsureWebViewIsInstalled() { + LPWSTR versionInfo = nullptr; + HRESULT ensureInstalledResult = GetAvailableCoreWebView2BrowserVersionString(nullptr, &versionInfo); + if (versionInfo != nullptr) + CoTaskMemFree(versionInfo); + + if (ensureInstalledResult != S_OK) + return InstallWebView2(); + + return true; +} + +bool InfiniFrameWindow::InstallWebView2() { + auto srcURL = L"https://go.microsoft.com/fwlink/p/?LinkId=2124703"; + auto destFile = L"MicrosoftEdgeWebview2Setup.exe"; + + if (S_OK == URLDownloadToFile(nullptr, srcURL, destFile, 0, nullptr)) { + std::wstring command = L"MicrosoftEdgeWebview2Setup.exe"; + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + bool success = CreateProcess( + nullptr, + command.data(), + nullptr, + nullptr, + FALSE, + 0, + nullptr, + nullptr, + &si, + &pi + ); + + if (success) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + return success; + } + + return false; +} + +void InfiniFrameWindow::SetWebView2RuntimePath(const AutoString pathToWebView2) { + if (pathToWebView2 == nullptr) + return; + + std::wstring widePath = Utf8ToWide(pathToWebView2); + std::lock_guard lock(webview2RuntimePathMutex); + wcsncpy_s(_webview2RuntimePath, widePath.c_str(), _countof(_webview2RuntimePath)); +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp deleted file mode 100644 index 863cc5435..000000000 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "Core/InfiniFrameDialog.h" -#include "Core/InfiniFrameWindow.h" -#include -#include "DarkMode.h" -#include "ToastHandler.h" -#include "Utils/Common.h" -#include "Window.Win32.Context.h" -#include "Window.Win32.Internal.h" - -#include "Embedded/Embedded.h" - -#pragma comment(lib, "Shcore.lib") -#pragma comment(lib, "Urlmon.lib") - -using namespace WinToastLib; -using namespace Microsoft::WRL; - -LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -const wchar_t* CLASS_NAME = L"InfiniFrame"; -std::atomic _hInstance{nullptr}; -thread_local HWND messageLoopRootWindowHandle = nullptr; -wchar_t _webview2RuntimePath[MAX_PATH]; -std::mutex webview2RuntimePathMutex; - -static_assert(sizeof(wchar_t) == sizeof(char16_t)); - -bool IsTeardownTraceEnabled() { - static const bool enabled = [] { - wchar_t value[32] = {}; - const DWORD len = GetEnvironmentVariableW(L"INFINIFRAME_TRACE_TEARDOWN", value, _countof(value)); - if (len == 0 || len >= _countof(value)) - return false; - - return _wcsicmp(value, L"1") == 0 - || _wcsicmp(value, L"true") == 0 - || _wcsicmp(value, L"yes") == 0 - || _wcsicmp(value, L"on") == 0; - }(); - - return enabled; -} - -void TraceTeardown(const wchar_t* format, ...) { - if (!IsTeardownTraceEnabled()) - return; - - wchar_t message[1024] = {}; - va_list args; - va_start(args, format); - _vsnwprintf_s(message, _countof(message), _TRUNCATE, format, args); - va_end(args); - - const std::wstring line = std::format( - L"[InfiniFrame][teardown][tid={}] {}\n", - GetCurrentThreadId(), - message - ); - OutputDebugStringW(line.c_str()); - std::fwprintf(stderr, L"%ls", line.c_str()); - std::fflush(stderr); -} - -std::wstring Utf8ToWide(const AutoString source) { - if (source == nullptr) - return {}; - - const auto* utf8 = reinterpret_cast(source); - const size_t utf8Length = strlen(utf8); - if (utf8Length == 0) - return {}; - - if (const auto validation = simdutf::validate_utf8_with_errors(utf8, utf8Length); validation.is_err()) - return {}; - - std::u16string utf16(simdutf::utf16_length_from_utf8(utf8, utf8Length), u'\0'); - const size_t written = simdutf::convert_valid_utf8_to_utf16( - utf8, - utf8Length, - reinterpret_cast(utf16.data()) - ); - utf16.resize(written); - - return { - reinterpret_cast(utf16.data()), - utf16.size() - }; -} - -std::string WideToUtf8(const AutoString source) { - if (source == nullptr) - return {}; - - const size_t utf16Length = wcslen(source); - if (utf16Length == 0) - return {}; - - const auto* utf16 = reinterpret_cast(source); - if (const auto validation = simdutf::validate_utf16_with_errors(utf16, utf16Length); validation.is_err()) - return {}; - - std::string utf8(simdutf::utf8_length_from_utf16(utf16, utf16Length), '\0'); - const size_t written = simdutf::convert_valid_utf16_to_utf8( - utf16, - utf16Length, - utf8.data() - ); - utf8.resize(written); - - return utf8; -} - -bool EnsureDirectoryWritable(const std::wstring& directoryPath) { - if (directoryPath.empty()) - return false; - - std::error_code createError; - std::filesystem::create_directories(directoryPath, createError); - if (createError) - return false; - - const std::wstring probePath = std::format( - L"{}\\{}.tmp", - directoryPath, - std::format(L".infiniframe-wv2-write-check-{}-{}-{}", GetCurrentProcessId(), GetCurrentThreadId(), GetTickCount64()) - ); - - HANDLE probeHandle = CreateFileW( - probePath.c_str(), - GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, - CREATE_ALWAYS, - FILE_ATTRIBUTE_TEMPORARY, - nullptr - ); - - if (probeHandle == INVALID_HANDLE_VALUE) - return false; - - CloseHandle(probeHandle); - DeleteFileW(probePath.c_str()); - return true; -} - -InfiniFrameWindow* LookupWindowInstance(const HWND hwnd) { - return reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); -} - -HWND ResolveParentWindowHandle(InfiniFrameWindow* parent) { - if (parent == nullptr) - return nullptr; - - HWND parentHwnd = parent->getHwnd(); - if (parentHwnd == nullptr || !IsWindow(parentHwnd)) - return nullptr; - - return parentHwnd; -} - -void InfiniFrameWindow::WaitForExit() { - ApplyPendingOwnerWindow(m_impl.get(), L"wait_for_exit"); - - messageLoopRootWindowHandle = m_impl->_hWnd; - TraceTeardown(L"WaitForExit start instance=%p hwnd=%p", this, m_impl->_hWnd); - - MSG msg = {}; - while (true) { - const int getMessageResult = GetMessage(&msg, nullptr, 0, 0); - if (getMessageResult == -1) { - TraceTeardown(L"WaitForExit GetMessage failed err=%lu", GetLastError()); - break; - } - if (getMessageResult == 0) - break; - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - messageLoopRootWindowHandle = nullptr; - TraceTeardown(L"WaitForExit end instance=%p hwnd=%p", this, m_impl->_hWnd); -} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowCore.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowCore.Win32.cpp new file mode 100644 index 000000000..0cfbda1b9 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowCore.Win32.cpp @@ -0,0 +1,10 @@ +#include "Utils/Common.h" +#include "Window.Win32.Context.h" + +static_assert(sizeof(wchar_t) == sizeof(char16_t)); + +const wchar_t* CLASS_NAME = L"InfiniFrame"; +std::atomic _hInstance{nullptr}; +thread_local HWND messageLoopRootWindowHandle = nullptr; +wchar_t _webview2RuntimePath[MAX_PATH]; +std::mutex webview2RuntimePathMutex; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEncoding.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEncoding.Win32.cpp new file mode 100644 index 000000000..9724e495f --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEncoding.Win32.cpp @@ -0,0 +1,56 @@ +#include +#include +#include + +#include + +#include "Window.Win32.Context.h" + +std::wstring Utf8ToWide(const AutoString source) { + if (source == nullptr) + return {}; + + const auto* utf8 = reinterpret_cast(source); + const size_t utf8Length = strlen(utf8); + if (utf8Length == 0) + return {}; + + if (const auto validation = simdutf::validate_utf8_with_errors(utf8, utf8Length); validation.is_err()) + return {}; + + std::u16string utf16(simdutf::utf16_length_from_utf8(utf8, utf8Length), u'\0'); + const size_t written = simdutf::convert_valid_utf8_to_utf16( + utf8, + utf8Length, + reinterpret_cast(utf16.data()) + ); + utf16.resize(written); + + return { + reinterpret_cast(utf16.data()), + utf16.size() + }; +} + +std::string WideToUtf8(const AutoString source) { + if (source == nullptr) + return {}; + + const size_t utf16Length = wcslen(source); + if (utf16Length == 0) + return {}; + + const auto* utf16 = reinterpret_cast(source); + if (const auto validation = simdutf::validate_utf16_with_errors(utf16, utf16Length); validation.is_err()) + return {}; + + std::string utf8(simdutf::utf8_length_from_utf16(utf16, utf16Length), '\0'); + const size_t written = simdutf::convert_valid_utf16_to_utf8( + utf16, + utf16Length, + utf8.data() + ); + utf8.resize(written); + + return utf8; +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowOwnership.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowOwnership.Win32.cpp new file mode 100644 index 000000000..1500f4a13 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowOwnership.Win32.cpp @@ -0,0 +1,16 @@ +#include "Window.Win32.Context.h" + +InfiniFrameWindow* LookupWindowInstance(const HWND hwnd) { + return reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); +} + +HWND ResolveParentWindowHandle(InfiniFrameWindow* parent) { + if (parent == nullptr) + return nullptr; + + HWND parentHwnd = parent->getHwnd(); + if (parentHwnd == nullptr || !IsWindow(parentHwnd)) + return nullptr; + + return parentHwnd; +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowStorage.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowStorage.Win32.cpp new file mode 100644 index 000000000..4216d1002 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowStorage.Win32.cpp @@ -0,0 +1,42 @@ +#include +#include + +#include "Window.Win32.Context.h" + +bool EnsureDirectoryWritable(const std::wstring& directoryPath) { + if (directoryPath.empty()) + return false; + + std::error_code createError; + std::filesystem::create_directories(directoryPath, createError); + if (createError) + return false; + + const std::wstring probePath = std::format( + L"{}\\{}.tmp", + directoryPath, + std::format( + L".infiniframe-wv2-write-check-{}-{}-{}", + GetCurrentProcessId(), + GetCurrentThreadId(), + GetTickCount64() + ) + ); + + HANDLE probeHandle = CreateFileW( + probePath.c_str(), + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + CREATE_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY, + nullptr + ); + + if (probeHandle == INVALID_HANDLE_VALUE) + return false; + + CloseHandle(probeHandle); + DeleteFileW(probePath.c_str()); + return true; +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowTracing.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowTracing.Win32.cpp new file mode 100644 index 000000000..9c0f5e061 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowTracing.Win32.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +#include "Window.Win32.Context.h" + +bool IsTeardownTraceEnabled() { + static const bool enabled = [] { + wchar_t value[32] = {}; + const DWORD len = GetEnvironmentVariableW(L"INFINIFRAME_TRACE_TEARDOWN", value, _countof(value)); + if (len == 0 || len >= _countof(value)) + return false; + + return _wcsicmp(value, L"1") == 0 + || _wcsicmp(value, L"true") == 0 + || _wcsicmp(value, L"yes") == 0 + || _wcsicmp(value, L"on") == 0; + }(); + + return enabled; +} + +void TraceTeardown(const wchar_t* format, ...) { + if (!IsTeardownTraceEnabled()) + return; + + wchar_t message[1024] = {}; + va_list args; + va_start(args, format); + _vsnwprintf_s(message, _countof(message), _TRUNCATE, format, args); + va_end(args); + + const std::wstring line = std::format( + L"[InfiniFrame][teardown][tid={}] {}\n", + GetCurrentThreadId(), + message + ); + OutputDebugStringW(line.c_str()); + std::fwprintf(stderr, L"%ls", line.c_str()); + std::fflush(stderr); +} From ba5b6edb06df6c626755386aae7b13b1bea95cc1 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 19:07:13 +0200 Subject: [PATCH 05/86] Remove platform-specific WebView implementations for Linux (GTK/WebKit) and macOS (Cocoa/WebKit); replace with modularized, cross-platform WebView bridge components. --- .../Native/CMakeLists.txt | 12 +- .../Platform/Linux/WebKit.Gtk.Internal.h | 18 ++ .../Platform/Linux/WebKitBridge.Gtk.cpp | 287 ------------------ .../Linux/WebKitCustomSchemes.Gtk.cpp | 54 ++++ .../Native/Platform/Linux/WebKitHost.Gtk.cpp | 99 ++++++ .../Platform/Linux/WebKitMessaging.Gtk.cpp | 49 +++ .../Platform/Linux/WebKitSettings.Gtk.cpp | 109 +++++++ .../Native/Platform/Mac/UiDispatcher.Cocoa.mm | 13 + .../Platform/Mac/WKCustomSchemes.Cocoa.mm | 22 ++ .../Platform/Mac/WKWebViewBridge.Cocoa.mm | 57 ++++ .../Platform/Mac/WKWebViewHost.Cocoa.mm | 69 +++++ .../Mac/{Window.mm => WindowCore.Cocoa.mm} | 167 +--------- .../Native/Platform/Mac/WindowEvents.Cocoa.mm | 8 - 13 files changed, 506 insertions(+), 458 deletions(-) create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit.Gtk.Internal.h delete mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitBridge.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitCustomSchemes.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitHost.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitMessaging.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitSettings.Gtk.cpp create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDispatcher.Cocoa.mm create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKCustomSchemes.Cocoa.mm create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewBridge.Cocoa.mm create mode 100644 src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewHost.Cocoa.mm rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{Window.mm => WindowCore.Cocoa.mm} (63%) diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index 947dfec61..77835c168 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -70,7 +70,10 @@ set(LINUX_SOURCES Platform/Linux/WindowState.Gtk.cpp Platform/Linux/WindowEvents.Gtk.cpp Platform/Linux/UiDispatcher.Gtk.cpp - Platform/Linux/WebKitBridge.Gtk.cpp + Platform/Linux/WebKitHost.Gtk.cpp + Platform/Linux/WebKitSettings.Gtk.cpp + Platform/Linux/WebKitMessaging.Gtk.cpp + Platform/Linux/WebKitCustomSchemes.Gtk.cpp Platform/Linux/WindowSignals.Gtk.cpp Platform/Linux/Dialog.cpp ) @@ -83,10 +86,14 @@ set(MAC_SOURCES Platform/Mac/UrlSchemeHandler.mm Platform/Mac/NSWindowBorderless.mm Platform/Mac/Dialog.mm - Platform/Mac/Window.mm + Platform/Mac/WindowCore.Cocoa.mm Platform/Mac/WindowLifecycle.Cocoa.mm Platform/Mac/WindowState.Cocoa.mm Platform/Mac/WindowEvents.Cocoa.mm + Platform/Mac/UiDispatcher.Cocoa.mm + Platform/Mac/WKWebViewBridge.Cocoa.mm + Platform/Mac/WKCustomSchemes.Cocoa.mm + Platform/Mac/WKWebViewHost.Cocoa.mm ) set(HEADER_FILES @@ -113,6 +120,7 @@ set(HEADER_FILES Platform/Mac/WindowDelegate.h Platform/Mac/UrlSchemeHandler.h Platform/Linux/Window.Gtk.Internal.h + Platform/Linux/WebKit.Gtk.Internal.h Platform/Mac/Window.Cocoa.Internal.h ) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit.Gtk.Internal.h new file mode 100644 index 000000000..ffb94ce49 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit.Gtk.Internal.h @@ -0,0 +1,18 @@ +#pragma once + +#ifndef INFINIFRAME_PLATFORM_LINUX_WEBKIT_GTK_INTERNAL_H +#define INFINIFRAME_PLATFORM_LINUX_WEBKIT_GTK_INTERNAL_H + +#include + +namespace gtk_webkit { + void HandleWebMessage( + WebKitUserContentManager* contentManager, + WebKitJavascriptResult* jsResult, + gpointer userData + ); + + void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, gpointer userData); +} + +#endif // INFINIFRAME_PLATFORM_LINUX_WEBKIT_GTK_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitBridge.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitBridge.Gtk.cpp deleted file mode 100644 index cdd879d5b..000000000 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitBridge.Gtk.cpp +++ /dev/null @@ -1,287 +0,0 @@ -#ifdef __linux__ - -#include -#include - -#include -#include -#include - -#include "Embedded/Embedded.h" -#include "Window.Gtk.Internal.h" - -extern void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data); -extern gboolean on_webview_load_failed( - WebKitWebView* web_view, - WebKitLoadEvent load_event, - gchar* failing_uri, - GError* error, - gpointer user_data - ); -extern void on_webview_process_terminated( - WebKitWebView* web_view, - WebKitWebProcessTerminationReason reason, - gpointer user_data - ); -extern void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data); - -namespace { - void HandleWebMessage( - WebKitUserContentManager* contentManager, - WebKitJavascriptResult* jsResult, - const gpointer userData - ) { - JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); - if (jsc_value_is_string(jsValue)) { - AutoString str_value = jsc_value_to_string(jsValue); - WebMessageReceivedCallback callback = reinterpret_cast(userData); - AutoString originValue = nullptr; - - JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); - JSStringRef script = JSStringCreateWithUTF8CString("window.location.href"); - JSValueRef locationValue = JSEvaluateScript(context, script, nullptr, nullptr, 0, nullptr); - JSStringRelease(script); - - if (locationValue != nullptr) { - JSStringRef locationString = JSValueToStringCopy(context, locationValue, nullptr); - if (locationString != nullptr) { - size_t maxBytes = JSStringGetMaximumUTF8CStringSize(locationString); - originValue = static_cast(g_malloc(maxBytes)); - JSStringGetUTF8CString(locationString, originValue, maxBytes); - JSStringRelease(locationString); - } - } - - if (callback != nullptr) { - callback(str_value, originValue); - } - - if (originValue != nullptr) - g_free(originValue); - - g_free(str_value); - } - webkit_javascript_result_unref(jsResult); - } - - void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { - WebResourceRequestedCallback webResourceRequestedCallback = reinterpret_cast( - user_data); - if (webResourceRequestedCallback == nullptr) { - GError* error = g_error_new_literal( - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "No custom scheme handler is registered."); - webkit_uri_scheme_request_finish_error(request, error); - g_error_free(error); - return; - } - - const gchar* uri = webkit_uri_scheme_request_get_uri(request); - int numBytes = 0; - AutoString contentType = nullptr; - void* dotNetResponse = webResourceRequestedCallback(const_cast(uri), &numBytes, &contentType); - GInputStream* stream = g_memory_input_stream_new_from_data(dotNetResponse, numBytes, nullptr); - webkit_uri_scheme_request_finish(request, reinterpret_cast(stream), -1, contentType); - g_object_unref(stream); - free(contentType); - } -} - -void InfiniFrameWindow::Impl::set_webkit_settings() { - WebKitSettings* settings = webkit_settings_new_with_settings( - "allow_modal_dialogs", TRUE, - "allow_top_navigation_to_data_urls", TRUE, - "allow_universal_access_from_file_urls", TRUE, - "enable_back_forward_navigation_gestures", TRUE, - "enable_media_capabilities", TRUE, - "enable_mock_capture_devices", TRUE, - "enable_page_cache", TRUE, - "enable_webrtc", TRUE, - "javascript_can_open_windows_automatically", TRUE, - - "allow_file_access_from_file_urls", _fileSystemAccessEnabled, - "disable_web_security", !_webSecurityEnabled, - "enable_developer_extras", _devToolsEnabled, - "enable_media_stream", _mediaStreamEnabled, - "enable_smooth_scrolling", _smoothScrollingEnabled, - "javascript_can_access_clipboard", _javascriptClipboardAccessEnabled, - "media_playback_requires_user_gesture", !_mediaAutoplayEnabled, - "user_agent", _userAgent.c_str(), - - NULL - ); - - if (!_browserControlInitParameters.empty()) - set_webkit_customsettings(settings); - - WebKitWebsiteDataManager* manager = webkit_web_view_get_website_data_manager(WEBKIT_WEB_VIEW(_webview)); - if (_ignoreCertificateErrorsEnabled) - webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_IGNORE); - else - webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_FAIL); - - webkit_web_view_set_settings(WEBKIT_WEB_VIEW(_webview), settings); -} - -void InfiniFrameWindow::Impl::set_webkit_customsettings(WebKitSettings* settings) { - try { - simdjson::ondemand::parser parser; - auto padded = simdjson::padded_string(_browserControlInitParameters); - auto doc = parser.iterate(padded); - - for (auto field : doc.get_object()) { - std::string_view keyView = field.unescaped_key(); - auto value = field.value(); - - gchar* propertyName = g_strdup(std::string(keyView).c_str()); - GValue propertyValue = G_VALUE_INIT; - bool hasValidValue = false; - - switch (value.type()) { - case simdjson::ondemand::json_type::string: { - std::string_view strVal; - if (value.get(strVal) == simdjson::SUCCESS) { - g_value_init(&propertyValue, G_TYPE_STRING); - g_value_set_string(&propertyValue, std::string(strVal).c_str()); - hasValidValue = true; - } - break; - } - case simdjson::ondemand::json_type::boolean: { - bool boolVal; - if (value.get(boolVal) == simdjson::SUCCESS) { - g_value_init(&propertyValue, G_TYPE_BOOLEAN); - g_value_set_boolean(&propertyValue, boolVal); - hasValidValue = true; - } - break; - } - case simdjson::ondemand::json_type::number: { - int64_t intVal; - if (value.get(intVal) == simdjson::SUCCESS) { - g_value_init(&propertyValue, G_TYPE_INT); - g_value_set_int(&propertyValue, static_cast(intVal)); - hasValidValue = true; - } - else { - double doubleVal; - if (value.get(doubleVal) == simdjson::SUCCESS) { - g_value_init(&propertyValue, G_TYPE_DOUBLE); - g_value_set_double(&propertyValue, doubleVal); - hasValidValue = true; - } - } - break; - } - default: - break; - } - - if (hasValidValue) { - g_object_set_property(G_OBJECT(settings), propertyName, &propertyValue); - g_value_unset(&propertyValue); - } - - g_free(propertyName); - } - } - catch (const simdjson::simdjson_error&) { - } -} - -void InfiniFrameWindow::Impl::AddCustomSchemeHandlers() { - if (_customSchemeCallback == nullptr) - return; - - WebKitWebContext* context = webkit_web_context_get_default(); - WebKitSecurityManager* securityManager = webkit_web_context_get_security_manager(context); - for (const auto& value : _customSchemeNames) { - if (securityManager != nullptr && g_ascii_strcasecmp(value.c_str(), "app") == 0) { - webkit_security_manager_register_uri_scheme_as_secure(securityManager, value.c_str()); - } - - webkit_web_context_register_uri_scheme( - context, value.c_str(), - reinterpret_cast(HandleCustomSchemeRequest), - reinterpret_cast(_customSchemeCallback), - nullptr - ); - } -} - -void InfiniFrameWindow::Show(bool isAlreadyShown) { - if (!m_impl->_webview) { - struct sigaction old_action; - sigaction(SIGCHLD, nullptr, &old_action); - WebKitUserContentManager* contentManager = webkit_user_content_manager_new(); - m_impl->_webview = webkit_web_view_new_with_user_content_manager(contentManager); - - m_impl->set_webkit_settings(); - - gtk_container_add(GTK_CONTAINER(m_impl->_window), m_impl->_webview); - gtk_widget_set_hexpand(m_impl->_webview, TRUE); - gtk_widget_set_vexpand(m_impl->_webview, TRUE); - - auto js = Embedded::InfiniFrameJsUtf8(); - - WebKitUserScript* script = webkit_user_script_new( - js.c_str(), - WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, - WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, - nullptr, - nullptr - ); - - webkit_user_content_manager_add_script(contentManager, script); - webkit_user_script_unref(script); - - g_signal_connect( - contentManager, "script-message-received::infiniFrameInterop", - G_CALLBACK(HandleWebMessage), - reinterpret_cast(m_impl->_webMessageReceivedCallback) - ); - webkit_user_content_manager_register_script_message_handler(contentManager, "infiniFrameInterop"); - - g_signal_connect( - G_OBJECT(m_impl->_webview), "load-changed", - G_CALLBACK(on_webview_load_changed), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "load-failed", - G_CALLBACK(on_webview_load_failed), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "web-process-terminated", - G_CALLBACK(on_webview_process_terminated), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "size-allocate", - G_CALLBACK(on_webview_size_allocate), this - ); - - if (!m_impl->_startUrl.empty()) - NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); - else if (!m_impl->_startString.empty()) - NavigateToString(const_cast(m_impl->_startString.c_str())); - else { - GtkWidget* dialog = gtk_message_dialog_new( - nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "Neither StartUrl nor StartString was specified" - ); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - sigaction(SIGCHLD, &old_action, nullptr); - return; - } - sigaction(SIGCHLD, &old_action, nullptr); - } - - gtk_widget_show_all(m_impl->_window); -} - -void InfiniFrameWindow::AttachWebView() { - // On Linux, WebView is attached in Show() -} - -#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitCustomSchemes.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitCustomSchemes.Gtk.cpp new file mode 100644 index 000000000..6194706fa --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitCustomSchemes.Gtk.cpp @@ -0,0 +1,54 @@ +#ifdef __linux__ + +#include +#include + +#include "Window.Gtk.Internal.h" +#include "WebKit.Gtk.Internal.h" + +namespace gtk_webkit { + void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { + WebResourceRequestedCallback webResourceRequestedCallback = reinterpret_cast( + user_data); + if (webResourceRequestedCallback == nullptr) { + GError* error = g_error_new_literal( + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "No custom scheme handler is registered."); + webkit_uri_scheme_request_finish_error(request, error); + g_error_free(error); + return; + } + + const gchar* uri = webkit_uri_scheme_request_get_uri(request); + int numBytes = 0; + AutoString contentType = nullptr; + void* dotNetResponse = webResourceRequestedCallback(const_cast(uri), &numBytes, &contentType); + GInputStream* stream = g_memory_input_stream_new_from_data(dotNetResponse, numBytes, nullptr); + webkit_uri_scheme_request_finish(request, reinterpret_cast(stream), -1, contentType); + g_object_unref(stream); + free(contentType); + } +} + +void InfiniFrameWindow::Impl::AddCustomSchemeHandlers() { + if (_customSchemeCallback == nullptr) + return; + + WebKitWebContext* context = webkit_web_context_get_default(); + WebKitSecurityManager* securityManager = webkit_web_context_get_security_manager(context); + for (const auto& value : _customSchemeNames) { + if (securityManager != nullptr && g_ascii_strcasecmp(value.c_str(), "app") == 0) { + webkit_security_manager_register_uri_scheme_as_secure(securityManager, value.c_str()); + } + + webkit_web_context_register_uri_scheme( + context, value.c_str(), + reinterpret_cast(gtk_webkit::HandleCustomSchemeRequest), + reinterpret_cast(_customSchemeCallback), + nullptr + ); + } +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitHost.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitHost.Gtk.cpp new file mode 100644 index 000000000..776008d13 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitHost.Gtk.cpp @@ -0,0 +1,99 @@ +#ifdef __linux__ + +#include +#include + +#include "Embedded/Embedded.h" +#include "WebKit.Gtk.Internal.h" +#include "Window.Gtk.Internal.h" + +extern void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data); +extern gboolean on_webview_load_failed( + WebKitWebView* web_view, + WebKitLoadEvent load_event, + gchar* failing_uri, + GError* error, + gpointer user_data + ); +extern void on_webview_process_terminated( + WebKitWebView* web_view, + WebKitWebProcessTerminationReason reason, + gpointer user_data + ); +extern void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data); + +void InfiniFrameWindow::Show(bool isAlreadyShown) { + if (!m_impl->_webview) { + struct sigaction old_action; + sigaction(SIGCHLD, nullptr, &old_action); + WebKitUserContentManager* contentManager = webkit_user_content_manager_new(); + m_impl->_webview = webkit_web_view_new_with_user_content_manager(contentManager); + + m_impl->set_webkit_settings(); + + gtk_container_add(GTK_CONTAINER(m_impl->_window), m_impl->_webview); + gtk_widget_set_hexpand(m_impl->_webview, TRUE); + gtk_widget_set_vexpand(m_impl->_webview, TRUE); + + auto js = Embedded::InfiniFrameJsUtf8(); + + WebKitUserScript* script = webkit_user_script_new( + js.c_str(), + WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, + WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, + nullptr, + nullptr + ); + + webkit_user_content_manager_add_script(contentManager, script); + webkit_user_script_unref(script); + + g_signal_connect( + contentManager, "script-message-received::infiniFrameInterop", + G_CALLBACK(gtk_webkit::HandleWebMessage), + reinterpret_cast(m_impl->_webMessageReceivedCallback) + ); + webkit_user_content_manager_register_script_message_handler(contentManager, "infiniFrameInterop"); + + g_signal_connect( + G_OBJECT(m_impl->_webview), "load-changed", + G_CALLBACK(on_webview_load_changed), this + ); + g_signal_connect( + G_OBJECT(m_impl->_webview), "load-failed", + G_CALLBACK(on_webview_load_failed), this + ); + g_signal_connect( + G_OBJECT(m_impl->_webview), "web-process-terminated", + G_CALLBACK(on_webview_process_terminated), this + ); + g_signal_connect( + G_OBJECT(m_impl->_webview), "size-allocate", + G_CALLBACK(on_webview_size_allocate), this + ); + + if (!m_impl->_startUrl.empty()) + NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); + else if (!m_impl->_startString.empty()) + NavigateToString(const_cast(m_impl->_startString.c_str())); + else { + GtkWidget* dialog = gtk_message_dialog_new( + nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "Neither StartUrl nor StartString was specified" + ); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + sigaction(SIGCHLD, &old_action, nullptr); + return; + } + sigaction(SIGCHLD, &old_action, nullptr); + } + + gtk_widget_show_all(m_impl->_window); +} + +void InfiniFrameWindow::AttachWebView() { + // On Linux, WebView is attached in Show() +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitMessaging.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitMessaging.Gtk.cpp new file mode 100644 index 000000000..7306257f7 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitMessaging.Gtk.cpp @@ -0,0 +1,49 @@ +#ifdef __linux__ + +#include +#include + +#include "Utils/Common.h" +#include "WebKit.Gtk.Internal.h" + +namespace gtk_webkit { + void HandleWebMessage( + WebKitUserContentManager* contentManager, + WebKitJavascriptResult* jsResult, + const gpointer userData + ) { + JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); + if (jsc_value_is_string(jsValue)) { + AutoString str_value = jsc_value_to_string(jsValue); + WebMessageReceivedCallback callback = reinterpret_cast(userData); + AutoString originValue = nullptr; + + JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); + JSStringRef script = JSStringCreateWithUTF8CString("window.location.href"); + JSValueRef locationValue = JSEvaluateScript(context, script, nullptr, nullptr, 0, nullptr); + JSStringRelease(script); + + if (locationValue != nullptr) { + JSStringRef locationString = JSValueToStringCopy(context, locationValue, nullptr); + if (locationString != nullptr) { + size_t maxBytes = JSStringGetMaximumUTF8CStringSize(locationString); + originValue = static_cast(g_malloc(maxBytes)); + JSStringGetUTF8CString(locationString, originValue, maxBytes); + JSStringRelease(locationString); + } + } + + if (callback != nullptr) { + callback(str_value, originValue); + } + + if (originValue != nullptr) + g_free(originValue); + + g_free(str_value); + } + webkit_javascript_result_unref(jsResult); + } +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitSettings.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitSettings.Gtk.cpp new file mode 100644 index 000000000..337b27ecb --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitSettings.Gtk.cpp @@ -0,0 +1,109 @@ +#ifdef __linux__ + +#include + +#include "Window.Gtk.Internal.h" + +void InfiniFrameWindow::Impl::set_webkit_settings() { + WebKitSettings* settings = webkit_settings_new_with_settings( + "allow_modal_dialogs", TRUE, + "allow_top_navigation_to_data_urls", TRUE, + "allow_universal_access_from_file_urls", TRUE, + "enable_back_forward_navigation_gestures", TRUE, + "enable_media_capabilities", TRUE, + "enable_mock_capture_devices", TRUE, + "enable_page_cache", TRUE, + "enable_webrtc", TRUE, + "javascript_can_open_windows_automatically", TRUE, + + "allow_file_access_from_file_urls", _fileSystemAccessEnabled, + "disable_web_security", !_webSecurityEnabled, + "enable_developer_extras", _devToolsEnabled, + "enable_media_stream", _mediaStreamEnabled, + "enable_smooth_scrolling", _smoothScrollingEnabled, + "javascript_can_access_clipboard", _javascriptClipboardAccessEnabled, + "media_playback_requires_user_gesture", !_mediaAutoplayEnabled, + "user_agent", _userAgent.c_str(), + + NULL + ); + + if (!_browserControlInitParameters.empty()) + set_webkit_customsettings(settings); + + WebKitWebsiteDataManager* manager = webkit_web_view_get_website_data_manager(WEBKIT_WEB_VIEW(_webview)); + if (_ignoreCertificateErrorsEnabled) + webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_IGNORE); + else + webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_FAIL); + + webkit_web_view_set_settings(WEBKIT_WEB_VIEW(_webview), settings); +} + +void InfiniFrameWindow::Impl::set_webkit_customsettings(WebKitSettings* settings) { + try { + simdjson::ondemand::parser parser; + auto padded = simdjson::padded_string(_browserControlInitParameters); + auto doc = parser.iterate(padded); + + for (auto field : doc.get_object()) { + std::string_view keyView = field.unescaped_key(); + auto value = field.value(); + + gchar* propertyName = g_strdup(std::string(keyView).c_str()); + GValue propertyValue = G_VALUE_INIT; + bool hasValidValue = false; + + switch (value.type()) { + case simdjson::ondemand::json_type::string: { + std::string_view strVal; + if (value.get(strVal) == simdjson::SUCCESS) { + g_value_init(&propertyValue, G_TYPE_STRING); + g_value_set_string(&propertyValue, std::string(strVal).c_str()); + hasValidValue = true; + } + break; + } + case simdjson::ondemand::json_type::boolean: { + bool boolVal; + if (value.get(boolVal) == simdjson::SUCCESS) { + g_value_init(&propertyValue, G_TYPE_BOOLEAN); + g_value_set_boolean(&propertyValue, boolVal); + hasValidValue = true; + } + break; + } + case simdjson::ondemand::json_type::number: { + int64_t intVal; + if (value.get(intVal) == simdjson::SUCCESS) { + g_value_init(&propertyValue, G_TYPE_INT); + g_value_set_int(&propertyValue, static_cast(intVal)); + hasValidValue = true; + } + else { + double doubleVal; + if (value.get(doubleVal) == simdjson::SUCCESS) { + g_value_init(&propertyValue, G_TYPE_DOUBLE); + g_value_set_double(&propertyValue, doubleVal); + hasValidValue = true; + } + } + break; + } + default: + break; + } + + if (hasValidValue) { + g_object_set_property(G_OBJECT(settings), propertyName, &propertyValue); + g_value_unset(&propertyValue); + } + + g_free(propertyName); + } + } + catch (const simdjson::simdjson_error&) { + } +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDispatcher.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDispatcher.Cocoa.mm new file mode 100644 index 000000000..a1ea73bcf --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDispatcher.Cocoa.mm @@ -0,0 +1,13 @@ +#ifdef __APPLE__ + +#include "Window.Cocoa.Internal.h" + +void InfiniFrameWindow::Invoke(ACTION callback) +{ + if ([NSThread isMainThread]) + callback(); + else + dispatch_sync(dispatch_get_main_queue(), ^(void){ callback(); }); +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKCustomSchemes.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKCustomSchemes.Cocoa.mm new file mode 100644 index 000000000..0e1eee49a --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKCustomSchemes.Cocoa.mm @@ -0,0 +1,22 @@ +#ifdef __APPLE__ + +#include "UrlSchemeHandler.h" +#include "Window.Cocoa.Internal.h" + +void InfiniFrameWindow::Impl::AddCustomScheme( + const AutoStringConst scheme, + WebResourceRequestedCallback requestHandler + ) +{ + if (requestHandler == nullptr) + return; + + UrlSchemeHandler* schemeHandler = [[[UrlSchemeHandler alloc] init] autorelease]; + schemeHandler->requestHandler = requestHandler; + + [_webviewConfiguration + setURLSchemeHandler: schemeHandler + forURLScheme: [NSString stringWithUTF8String: scheme]]; +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewBridge.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewBridge.Cocoa.mm new file mode 100644 index 000000000..25e77af76 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewBridge.Cocoa.mm @@ -0,0 +1,57 @@ +#ifdef __APPLE__ + +#include + +#include "Window.Cocoa.Internal.h" + +std::vector InfiniFrameWindow::Impl::GetMonitors() const +{ + std::vector monitors; + + for (NSScreen *screen : [NSScreen screens]) + { + NSRect monitorFrame = [screen frame]; + Monitor::MonitorRect monitorArea; + monitorArea.x = static_cast(roundf(monitorFrame.origin.x)); + monitorArea.y = static_cast(roundf(monitorFrame.origin.y)); + monitorArea.width = static_cast(roundf(monitorFrame.size.width)); + monitorArea.height = static_cast(roundf(monitorFrame.size.height)); + + NSRect workFrame = [screen visibleFrame]; + Monitor::MonitorRect workArea; + workArea.x = static_cast(roundf(workFrame.origin.x)); + workArea.y = static_cast(roundf(workFrame.origin.y)); + workArea.width = static_cast(roundf(workFrame.size.width)); + workArea.height = static_cast(roundf(workFrame.size.height)); + + CGFloat scaleFactor = [screen backingScaleFactor]; + monitors.push_back({monitorArea, workArea, static_cast(scaleFactor)}); + } + + return monitors; +} + +void InfiniFrameWindow::Impl::SetUserAgent(AutoString userAgent) +{ + if (userAgent != nullptr) + { + _userAgent = userAgent; + [_webview setCustomUserAgent: [NSString stringWithUTF8String: userAgent]]; + } + else + { + _userAgent.clear(); + } +} + +void InfiniFrameWindow::Impl::SetPreference(NSString *key, NSNumber *value) +{ + [_webviewConfiguration.preferences setValue: value forKey: key]; +} + +void InfiniFrameWindow::Impl::SetPreference(NSString *key, NSString *value) +{ + [_webviewConfiguration.preferences setValue: value forKey: key]; +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewHost.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewHost.Cocoa.mm new file mode 100644 index 000000000..0546aaeb8 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewHost.Cocoa.mm @@ -0,0 +1,69 @@ +#ifdef __APPLE__ + +#include "Embedded/Embedded.h" +#include "NavigationDelegate.h" +#include "UiDelegate.h" +#include "Window.Cocoa.Internal.h" + +void InfiniFrameWindow::AttachWebView() +{ + auto js = Embedded::InfiniFrameJsUtf8(); + + WKUserScript *script = + [[WKUserScript alloc] + initWithSource:[NSString stringWithUTF8String:js.c_str()] + injectionTime:WKUserScriptInjectionTimeAtDocumentStart + forMainFrameOnly:NO]; + + WKUserContentController *userContentController = + [[WKUserContentController alloc] init]; + + [userContentController addUserScript:script]; + + m_impl->_webviewConfiguration.userContentController = userContentController; + + m_impl->_webview = [ + [WKWebView alloc] + initWithFrame: m_impl->_window.contentView.frame + configuration: m_impl->_webviewConfiguration]; + + [m_impl->_webview setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; + [m_impl->_window.contentView addSubview: m_impl->_webview]; + [m_impl->_window.contentView setAutoresizesSubviews: true]; + + UiDelegate *uiDelegate = [[[UiDelegate alloc] init] autorelease]; + uiDelegate->infiniFrame = this; + uiDelegate->window = m_impl->_window; + uiDelegate->webMessageReceivedCallback = m_impl->_webMessageReceivedCallback; + + NavigationDelegate *navDelegate = [[[NavigationDelegate alloc] init] autorelease]; + navDelegate->infiniFrame = this; + navDelegate->window = m_impl->_window; + + [userContentController addScriptMessageHandler: uiDelegate name: @"infiniFrameInterop"]; + + m_impl->_webview.UIDelegate = uiDelegate; + m_impl->_webview.navigationDelegate = navDelegate; + + if (!m_impl->_startUrl.empty()) + NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); + else if (!m_impl->_startString.empty()) + NavigateToString(const_cast(m_impl->_startString.c_str())); + else + { + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + [alert setMessageText: @"Neither StartUrl nor StartString was specified"]; + [alert runModal]; + } +} + +void InfiniFrameWindow::Show(bool isAlreadyShown) +{ + if (m_impl->_webview == nil) + AttachWebView(); + + [m_impl->_window makeKeyAndOrderFront: m_impl->_window]; + [m_impl->_window orderFrontRegardless]; +} + +#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowCore.Cocoa.mm similarity index 63% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowCore.Cocoa.mm index 92c80013a..cd4557828 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowCore.Cocoa.mm @@ -1,90 +1,13 @@ #ifdef __APPLE__ -#include "Core/InfiniFrameWindow.h" + +#include + +#include "AppDelegate.h" #include "Core/InfiniFrameDialog.h" -#include "Embedded/Embedded.h" -#include "Utils/Common.h" +#include "Core/InfiniFrameWindow.h" +#include "NSWindowBorderless.h" #include "Window.Cocoa.Internal.h" -#include "AppDelegate.h" -#include "UiDelegate.h" #include "WindowDelegate.h" -#include "UrlSchemeHandler.h" -#include "NSWindowBorderless.h" -#include "NavigationDelegate.h" -#include -#include - -using namespace std; - -// --------------------------------------------------------------------------------------------------------------------- -// Impl method definitions -// --------------------------------------------------------------------------------------------------------------------- - -std::vector InfiniFrameWindow::Impl::GetMonitors() const -{ - std::vector monitors; - - for (NSScreen *screen : [NSScreen screens]) - { - NSRect monitorFrame = [screen frame]; - Monitor::MonitorRect monitorArea; - monitorArea.x = static_cast(roundf(monitorFrame.origin.x)); - monitorArea.y = static_cast(roundf(monitorFrame.origin.y)); - monitorArea.width = static_cast(roundf(monitorFrame.size.width)); - monitorArea.height = static_cast(roundf(monitorFrame.size.height)); - - NSRect workFrame = [screen visibleFrame]; - Monitor::MonitorRect workArea; - workArea.x = static_cast(roundf(workFrame.origin.x)); - workArea.y = static_cast(roundf(workFrame.origin.y)); - workArea.width = static_cast(roundf(workFrame.size.width)); - workArea.height = static_cast(roundf(workFrame.size.height)); - - CGFloat scaleFactor = [screen backingScaleFactor]; - monitors.push_back({monitorArea, workArea, static_cast(scaleFactor)}); - } - - return monitors; -} - -void InfiniFrameWindow::Impl::SetUserAgent(AutoString userAgent) -{ - if (userAgent != nullptr) - { - _userAgent = userAgent; - [_webview setCustomUserAgent: [NSString stringWithUTF8String: userAgent]]; - } - else - { - _userAgent.clear(); - } -} - -void InfiniFrameWindow::Impl::SetPreference(NSString *key, NSNumber *value) -{ - [_webviewConfiguration.preferences setValue: value forKey: key]; -} - -void InfiniFrameWindow::Impl::SetPreference(NSString *key, NSString *value) -{ - [_webviewConfiguration.preferences setValue: value forKey: key]; -} - -void InfiniFrameWindow::Impl::AddCustomScheme(const AutoStringConst scheme, WebResourceRequestedCallback requestHandler) -{ - if (requestHandler == nullptr) - return; - - UrlSchemeHandler* schemeHandler = [[[UrlSchemeHandler alloc] init] autorelease]; - schemeHandler->requestHandler = requestHandler; - - [_webviewConfiguration - setURLSchemeHandler: schemeHandler - forURLScheme: [NSString stringWithUTF8String: scheme]]; -} - -// --------------------------------------------------------------------------------------------------------------------- -// Register (static — called once) -// --------------------------------------------------------------------------------------------------------------------- void InfiniFrameWindow::Register() { @@ -148,10 +71,6 @@ [NSApp setMainMenu: mainMenu]; } -// --------------------------------------------------------------------------------------------------------------------- -// Constructor / Destructor -// --------------------------------------------------------------------------------------------------------------------- - InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) : m_impl(std::make_unique()) { m_impl->_windowTitle = initParams->Title ? initParams->Title : ""; @@ -284,11 +203,6 @@ for (const auto & scheme : m_impl->_customSchemeNames) { - // Note: - // Unlike WebView2 (Windows) and WebKitGTK (Linux security manager), - // WKURLSchemeHandler does not expose per-scheme "secure"/authority flags. - // We still register all custom schemes here for routing, but "app" trust - // semantics cannot be configured at the same granularity on macOS. m_impl->AddCustomScheme(scheme.c_str(), m_impl->_customSchemeCallback); } @@ -383,73 +297,4 @@ [m_impl->_window performClose: m_impl->_window]; } -// --------------------------------------------------------------------------------------------------------------------- -// Window Operations -// --------------------------------------------------------------------------------------------------------------------- - -// --------------------------------------------------------------------------------------------------------------------- -// Private methods -// --------------------------------------------------------------------------------------------------------------------- - -void InfiniFrameWindow::AttachWebView() -{ - auto js = Embedded::InfiniFrameJsUtf8(); - - WKUserScript *script = - [[WKUserScript alloc] - initWithSource:[NSString stringWithUTF8String:js.c_str()] - injectionTime:WKUserScriptInjectionTimeAtDocumentStart - forMainFrameOnly:NO]; - - WKUserContentController *userContentController = - [[WKUserContentController alloc] init]; - - [userContentController addUserScript:script]; - - m_impl->_webviewConfiguration.userContentController = userContentController; - - m_impl->_webview = [ - [WKWebView alloc] - initWithFrame: m_impl->_window.contentView.frame - configuration: m_impl->_webviewConfiguration]; - - [m_impl->_webview setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; - [m_impl->_window.contentView addSubview: m_impl->_webview]; - [m_impl->_window.contentView setAutoresizesSubviews: true]; - - UiDelegate *uiDelegate = [[[UiDelegate alloc] init] autorelease]; - uiDelegate->infiniFrame = this; - uiDelegate->window = m_impl->_window; - uiDelegate->webMessageReceivedCallback = m_impl->_webMessageReceivedCallback; - - NavigationDelegate *navDelegate = [[[NavigationDelegate alloc] init] autorelease]; - navDelegate->infiniFrame = this; - navDelegate->window = m_impl->_window; - - [userContentController addScriptMessageHandler: uiDelegate name: @"infiniFrameInterop"]; - - m_impl->_webview.UIDelegate = uiDelegate; - m_impl->_webview.navigationDelegate = navDelegate; - - if (!m_impl->_startUrl.empty()) - NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); - else if (!m_impl->_startString.empty()) - NavigateToString(const_cast(m_impl->_startString.c_str())); - else - { - NSAlert *alert = [[[NSAlert alloc] init] autorelease]; - [alert setMessageText: @"Neither StartUrl nor StartString was specified"]; - [alert runModal]; - } -} - -void InfiniFrameWindow::Show(bool isAlreadyShown) -{ - if (m_impl->_webview == nil) - AttachWebView(); - - [m_impl->_window makeKeyAndOrderFront: m_impl->_window]; - [m_impl->_window orderFrontRegardless]; -} - #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm index f9b57e617..631baae36 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm @@ -85,14 +85,6 @@ m_impl->_minimizedCallback = callback; } -void InfiniFrameWindow::Invoke(ACTION callback) -{ - if ([NSThread isMainThread]) - callback(); - else - dispatch_sync(dispatch_get_main_queue(), ^(void){ callback(); }); -} - [[nodiscard]] bool InfiniFrameWindow::InvokeClose() const noexcept { if (m_impl->_closingCallback) From c4ac53c380a8a5d2181a909327a6302dbb19c873 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 19:14:03 +0200 Subject: [PATCH 06/86] Remove platform-specific UI dispatcher and WebView implementations (Windows, macOS, Linux), preparing for a unified, modularized bridge. --- .../Native/CMakeLists.txt | 68 +++++++++---------- .../Linux/{ => Core}/UiDispatcher.Gtk.cpp | 2 +- .../Linux/{ => Core}/WindowCore.Gtk.cpp | 2 +- .../Linux/{ => Core}/WindowEvents.Gtk.cpp | 2 +- .../{ => Core}/WindowInitialization.Gtk.cpp | 4 +- .../Linux/{ => Core}/WindowLifecycle.Gtk.cpp | 2 +- .../Linux/{ => Core}/WindowSignals.Gtk.cpp | 2 +- .../Linux/{ => Core}/WindowState.Gtk.cpp | 4 +- .../Linux/{ => WebKit}/WebKit.Gtk.Internal.h | 0 .../{ => WebKit}/WebKitCustomSchemes.Gtk.cpp | 2 +- .../Linux/{ => WebKit}/WebKitHost.Gtk.cpp | 4 +- .../{ => WebKit}/WebKitMessaging.Gtk.cpp | 2 +- .../Linux/{ => WebKit}/WebKitSettings.Gtk.cpp | 2 +- .../Mac/{ => Core}/UiDispatcher.Cocoa.mm | 2 +- .../Mac/{ => Core}/WindowCore.Cocoa.mm | 12 ++-- .../Mac/{ => Core}/WindowEvents.Cocoa.mm | 2 +- .../Mac/{ => Core}/WindowLifecycle.Cocoa.mm | 2 +- .../Mac/{ => Core}/WindowState.Cocoa.mm | 2 +- .../Mac/{ => WK}/WKCustomSchemes.Cocoa.mm | 4 +- .../Mac/{ => WK}/WKWebViewBridge.Cocoa.mm | 2 +- .../Mac/{ => WK}/WKWebViewHost.Cocoa.mm | 8 +-- .../Windows/{ => Core}/UiDispatcher.Win32.cpp | 2 +- .../Windows/{ => Core}/WindowCore.Win32.cpp | 4 +- .../{ => Core}/WindowEncoding.Win32.cpp | 2 +- .../Windows/{ => Core}/WindowEvents.Win32.cpp | 2 +- .../{ => Core}/WindowLifecycle.Win32.cpp | 4 +- .../{ => Core}/WindowOwnership.Win32.cpp | 2 +- .../Windows/{ => Core}/WindowProc.Win32.cpp | 4 +- .../Windows/{ => Core}/WindowState.Win32.cpp | 4 +- .../{ => Core}/WindowStorage.Win32.cpp | 2 +- .../{ => Core}/WindowTracing.Win32.cpp | 2 +- .../{ => WebView}/WebView2Attach.Win32.cpp | 4 +- .../WebView2Controller.Win32.cpp | 2 +- .../{ => WebView}/WebView2Host.Win32.cpp | 2 +- .../{ => WebView}/WebView2Runtime.Win32.cpp | 2 +- 35 files changed, 84 insertions(+), 84 deletions(-) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => Core}/UiDispatcher.Gtk.cpp (96%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => Core}/WindowCore.Gtk.cpp (97%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => Core}/WindowEvents.Gtk.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => Core}/WindowInitialization.Gtk.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => Core}/WindowLifecycle.Gtk.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => Core}/WindowSignals.Gtk.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => Core}/WindowState.Gtk.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => WebKit}/WebKit.Gtk.Internal.h (100%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => WebKit}/WebKitCustomSchemes.Gtk.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => WebKit}/WebKitHost.Gtk.cpp (97%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => WebKit}/WebKitMessaging.Gtk.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Linux/{ => WebKit}/WebKitSettings.Gtk.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{ => Core}/UiDispatcher.Cocoa.mm (84%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{ => Core}/WindowCore.Cocoa.mm (97%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{ => Core}/WindowEvents.Cocoa.mm (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{ => Core}/WindowLifecycle.Cocoa.mm (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{ => Core}/WindowState.Cocoa.mm (99%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{ => WK}/WKCustomSchemes.Cocoa.mm (87%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{ => WK}/WKWebViewBridge.Cocoa.mm (97%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{ => WK}/WKWebViewHost.Cocoa.mm (94%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/UiDispatcher.Win32.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowCore.Win32.cpp (79%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowEncoding.Win32.cpp (97%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowEvents.Win32.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowLifecycle.Win32.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowOwnership.Win32.cpp (91%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowProc.Win32.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowState.Win32.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowStorage.Win32.cpp (96%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => Core}/WindowTracing.Win32.cpp (96%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => WebView}/WebView2Attach.Win32.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => WebView}/WebView2Controller.Win32.cpp (97%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => WebView}/WebView2Host.Win32.cpp (97%) rename src/InfiniFrame.NativeBridge/Native/Platform/Windows/{ => WebView}/WebView2Runtime.Win32.cpp (97%) diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index 77835c168..a20591d47 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -45,36 +45,36 @@ set(TEST_SOURCES ) set(WINDOWS_SOURCES - Platform/Windows/WindowCore.Win32.cpp - Platform/Windows/WindowTracing.Win32.cpp - Platform/Windows/WindowEncoding.Win32.cpp - Platform/Windows/WindowStorage.Win32.cpp - Platform/Windows/WindowOwnership.Win32.cpp - Platform/Windows/WindowLifecycle.Win32.cpp - Platform/Windows/WindowProc.Win32.cpp - Platform/Windows/WindowState.Win32.cpp - Platform/Windows/WindowEvents.Win32.cpp - Platform/Windows/WebView2Host.Win32.cpp - Platform/Windows/WebView2Runtime.Win32.cpp - Platform/Windows/WebView2Controller.Win32.cpp - Platform/Windows/WebView2Attach.Win32.cpp - Platform/Windows/UiDispatcher.Win32.cpp + Platform/Windows/Core/WindowCore.Win32.cpp + Platform/Windows/Core/WindowTracing.Win32.cpp + Platform/Windows/Core/WindowEncoding.Win32.cpp + Platform/Windows/Core/WindowStorage.Win32.cpp + Platform/Windows/Core/WindowOwnership.Win32.cpp + Platform/Windows/Core/WindowLifecycle.Win32.cpp + Platform/Windows/Core/WindowProc.Win32.cpp + Platform/Windows/Core/WindowState.Win32.cpp + Platform/Windows/Core/WindowEvents.Win32.cpp + Platform/Windows/WebView/WebView2Host.Win32.cpp + Platform/Windows/WebView/WebView2Runtime.Win32.cpp + Platform/Windows/WebView/WebView2Controller.Win32.cpp + Platform/Windows/WebView/WebView2Attach.Win32.cpp + Platform/Windows/Core/UiDispatcher.Win32.cpp Platform/Windows/DarkMode.cpp Platform/Windows/Dialog.cpp ) set(LINUX_SOURCES - Platform/Linux/WindowCore.Gtk.cpp - Platform/Linux/WindowInitialization.Gtk.cpp - Platform/Linux/WindowLifecycle.Gtk.cpp - Platform/Linux/WindowState.Gtk.cpp - Platform/Linux/WindowEvents.Gtk.cpp - Platform/Linux/UiDispatcher.Gtk.cpp - Platform/Linux/WebKitHost.Gtk.cpp - Platform/Linux/WebKitSettings.Gtk.cpp - Platform/Linux/WebKitMessaging.Gtk.cpp - Platform/Linux/WebKitCustomSchemes.Gtk.cpp - Platform/Linux/WindowSignals.Gtk.cpp + Platform/Linux/Core/WindowCore.Gtk.cpp + Platform/Linux/Core/WindowInitialization.Gtk.cpp + Platform/Linux/Core/WindowLifecycle.Gtk.cpp + Platform/Linux/Core/WindowState.Gtk.cpp + Platform/Linux/Core/WindowEvents.Gtk.cpp + Platform/Linux/Core/UiDispatcher.Gtk.cpp + Platform/Linux/WebKit/WebKitHost.Gtk.cpp + Platform/Linux/WebKit/WebKitSettings.Gtk.cpp + Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp + Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp + Platform/Linux/Core/WindowSignals.Gtk.cpp Platform/Linux/Dialog.cpp ) @@ -86,14 +86,14 @@ set(MAC_SOURCES Platform/Mac/UrlSchemeHandler.mm Platform/Mac/NSWindowBorderless.mm Platform/Mac/Dialog.mm - Platform/Mac/WindowCore.Cocoa.mm - Platform/Mac/WindowLifecycle.Cocoa.mm - Platform/Mac/WindowState.Cocoa.mm - Platform/Mac/WindowEvents.Cocoa.mm - Platform/Mac/UiDispatcher.Cocoa.mm - Platform/Mac/WKWebViewBridge.Cocoa.mm - Platform/Mac/WKCustomSchemes.Cocoa.mm - Platform/Mac/WKWebViewHost.Cocoa.mm + Platform/Mac/Core/WindowCore.Cocoa.mm + Platform/Mac/Core/WindowLifecycle.Cocoa.mm + Platform/Mac/Core/WindowState.Cocoa.mm + Platform/Mac/Core/WindowEvents.Cocoa.mm + Platform/Mac/Core/UiDispatcher.Cocoa.mm + Platform/Mac/WK/WKWebViewBridge.Cocoa.mm + Platform/Mac/WK/WKCustomSchemes.Cocoa.mm + Platform/Mac/WK/WKWebViewHost.Cocoa.mm ) set(HEADER_FILES @@ -120,7 +120,7 @@ set(HEADER_FILES Platform/Mac/WindowDelegate.h Platform/Mac/UrlSchemeHandler.h Platform/Linux/Window.Gtk.Internal.h - Platform/Linux/WebKit.Gtk.Internal.h + Platform/Linux/WebKit/WebKit.Gtk.Internal.h Platform/Mac/Window.Cocoa.Internal.h ) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/UiDispatcher.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp similarity index 96% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/UiDispatcher.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp index b13a74fb6..3b33bd38a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/UiDispatcher.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp @@ -3,7 +3,7 @@ #include #include -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" namespace { std::mutex invokeLockMutex; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowCore.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowCore.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp index 665adbe30..d484036a0 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowCore.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp @@ -3,7 +3,7 @@ #include #include -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) : m_impl(std::make_unique()) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowEvents.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowEvents.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp index 4770bf254..1389b8b47 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowEvents.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp @@ -1,6 +1,6 @@ #ifdef __linux__ -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" InfiniFrameDialog* InfiniFrameWindow::GetDialog() const { return m_impl->_dialog.get(); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowInitialization.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowInitialization.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp index 1c164ee62..ccd4a63e7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowInitialization.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp @@ -2,8 +2,8 @@ #include -#include "Core/InfiniFrameDialog.h" -#include "Window.Gtk.Internal.h" +#include "../../../Core/InfiniFrameDialog.h" +#include "../Window.Gtk.Internal.h" gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, gpointer self); gboolean on_window_state_event(GtkWidget* widget, GdkEventWindowState* event, gpointer self); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowLifecycle.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowLifecycle.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp index 8b6d7d047..7b500b14e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowLifecycle.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp @@ -1,6 +1,6 @@ #ifdef __linux__ -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" #include diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowSignals.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowSignals.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp index bb4d6287c..222f62609 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowSignals.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp @@ -2,7 +2,7 @@ #include -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" namespace { bool linux_webview_diagnostics_enabled() { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowState.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowState.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp index 7cc329ac7..0d530ce82 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WindowState.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp @@ -1,11 +1,11 @@ #ifdef __linux__ -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" #include #include -#include "Utils/Common.h" +#include "../../../Utils/Common.h" void InfiniFrameWindow::GetTransparentEnabled(bool* enabled) const { *enabled = m_impl->_transparentEnabled; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit.Gtk.Internal.h rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitCustomSchemes.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitCustomSchemes.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp index 6194706fa..4aa36a8f9 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitCustomSchemes.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp @@ -3,7 +3,7 @@ #include #include -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" #include "WebKit.Gtk.Internal.h" namespace gtk_webkit { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitHost.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitHost.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp index 776008d13..8b2bb827e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitHost.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp @@ -3,9 +3,9 @@ #include #include -#include "Embedded/Embedded.h" +#include "../../../Embedded/Embedded.h" #include "WebKit.Gtk.Internal.h" -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" extern void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data); extern gboolean on_webview_load_failed( diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitMessaging.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitMessaging.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp index 7306257f7..1480f4fd7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitMessaging.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp @@ -3,7 +3,7 @@ #include #include -#include "Utils/Common.h" +#include "../../../Utils/Common.h" #include "WebKit.Gtk.Internal.h" namespace gtk_webkit { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitSettings.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitSettings.Gtk.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp index 337b27ecb..eacfd60a8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKitSettings.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp @@ -2,7 +2,7 @@ #include -#include "Window.Gtk.Internal.h" +#include "../Window.Gtk.Internal.h" void InfiniFrameWindow::Impl::set_webkit_settings() { WebKitSettings* settings = webkit_settings_new_with_settings( diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDispatcher.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/UiDispatcher.Cocoa.mm similarity index 84% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDispatcher.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/UiDispatcher.Cocoa.mm index a1ea73bcf..6ef3bea97 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDispatcher.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/UiDispatcher.Cocoa.mm @@ -1,6 +1,6 @@ #ifdef __APPLE__ -#include "Window.Cocoa.Internal.h" +#include "../Window.Cocoa.Internal.h" void InfiniFrameWindow::Invoke(ACTION callback) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowCore.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowCore.Cocoa.mm similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowCore.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowCore.Cocoa.mm index cd4557828..03703eed7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowCore.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowCore.Cocoa.mm @@ -2,12 +2,12 @@ #include -#include "AppDelegate.h" -#include "Core/InfiniFrameDialog.h" -#include "Core/InfiniFrameWindow.h" -#include "NSWindowBorderless.h" -#include "Window.Cocoa.Internal.h" -#include "WindowDelegate.h" +#include "../AppDelegate.h" +#include "../../../Core/InfiniFrameDialog.h" +#include "../../../Core/InfiniFrameWindow.h" +#include "../NSWindowBorderless.h" +#include "../Window.Cocoa.Internal.h" +#include "../WindowDelegate.h" void InfiniFrameWindow::Register() { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowEvents.Cocoa.mm similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowEvents.Cocoa.mm index 631baae36..ee92e136b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowEvents.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowEvents.Cocoa.mm @@ -1,6 +1,6 @@ #ifdef __APPLE__ -#include "Window.Cocoa.Internal.h" +#include "../Window.Cocoa.Internal.h" InfiniFrameDialog* InfiniFrameWindow::GetDialog() const { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowLifecycle.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowLifecycle.Cocoa.mm similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowLifecycle.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowLifecycle.Cocoa.mm index d85e661e9..20e1e9f36 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowLifecycle.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowLifecycle.Cocoa.mm @@ -1,6 +1,6 @@ #ifdef __APPLE__ -#include "Window.Cocoa.Internal.h" +#include "../Window.Cocoa.Internal.h" void InfiniFrameWindow::Center() { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowState.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowState.Cocoa.mm similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowState.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowState.Cocoa.mm index f4e339432..a72a33cef 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowState.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowState.Cocoa.mm @@ -1,6 +1,6 @@ #ifdef __APPLE__ -#include "Window.Cocoa.Internal.h" +#include "../Window.Cocoa.Internal.h" #include "Utils/Common.h" diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKCustomSchemes.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKCustomSchemes.Cocoa.mm similarity index 87% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKCustomSchemes.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKCustomSchemes.Cocoa.mm index 0e1eee49a..e7401b90c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKCustomSchemes.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKCustomSchemes.Cocoa.mm @@ -1,7 +1,7 @@ #ifdef __APPLE__ -#include "UrlSchemeHandler.h" -#include "Window.Cocoa.Internal.h" +#include "../UrlSchemeHandler.h" +#include "../Window.Cocoa.Internal.h" void InfiniFrameWindow::Impl::AddCustomScheme( const AutoStringConst scheme, diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewBridge.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewBridge.Cocoa.mm similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewBridge.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewBridge.Cocoa.mm index 25e77af76..1a2b8f684 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewBridge.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewBridge.Cocoa.mm @@ -2,7 +2,7 @@ #include -#include "Window.Cocoa.Internal.h" +#include "../Window.Cocoa.Internal.h" std::vector InfiniFrameWindow::Impl::GetMonitors() const { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewHost.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewHost.Cocoa.mm similarity index 94% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewHost.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewHost.Cocoa.mm index 0546aaeb8..44f01e90c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WKWebViewHost.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewHost.Cocoa.mm @@ -1,9 +1,9 @@ #ifdef __APPLE__ -#include "Embedded/Embedded.h" -#include "NavigationDelegate.h" -#include "UiDelegate.h" -#include "Window.Cocoa.Internal.h" +#include "../../../Embedded/Embedded.h" +#include "../NavigationDelegate.h" +#include "../UiDelegate.h" +#include "../Window.Cocoa.Internal.h" void InfiniFrameWindow::AttachWebView() { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp index 1f58dc3d9..ee1d2da9b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/UiDispatcher.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp @@ -1,6 +1,6 @@ #include -#include "Window.Win32.Context.h" +#include "../Window.Win32.Context.h" void InfiniFrameWindow::WaitForExit() { ApplyPendingOwnerWindow(m_impl.get(), L"wait_for_exit"); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowCore.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowCore.Win32.cpp similarity index 79% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowCore.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowCore.Win32.cpp index 0cfbda1b9..498078aaf 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowCore.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowCore.Win32.cpp @@ -1,5 +1,5 @@ -#include "Utils/Common.h" -#include "Window.Win32.Context.h" +#include "../../../Utils/Common.h" +#include "../Window.Win32.Context.h" static_assert(sizeof(wchar_t) == sizeof(char16_t)); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEncoding.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEncoding.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp index 9724e495f..e145a71a4 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEncoding.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp @@ -4,7 +4,7 @@ #include -#include "Window.Win32.Context.h" +#include "../Window.Win32.Context.h" std::wstring Utf8ToWide(const AutoString source) { if (source == nullptr) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEvents.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEvents.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp index fa8d7fd9a..f4a5e9e97 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowEvents.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp @@ -1,4 +1,4 @@ -#include "Window.Win32.Internal.h" +#include "../Window.Win32.Internal.h" #include diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowLifecycle.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowLifecycle.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp index 59f8da863..540582a21 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowLifecycle.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp @@ -1,7 +1,7 @@ #include -#include "DarkMode.h" -#include "Window.Win32.Context.h" +#include "../DarkMode.h" +#include "../Window.Win32.Context.h" using namespace WinToastLib; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowOwnership.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowOwnership.Win32.cpp similarity index 91% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowOwnership.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowOwnership.Win32.cpp index 1500f4a13..349e8ea58 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowOwnership.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowOwnership.Win32.cpp @@ -1,4 +1,4 @@ -#include "Window.Win32.Context.h" +#include "../Window.Win32.Context.h" InfiniFrameWindow* LookupWindowInstance(const HWND hwnd) { return reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowProc.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowProc.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp index 6726a5727..a4696078b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowProc.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp @@ -1,5 +1,5 @@ -#include "DarkMode.h" -#include "Window.Win32.Context.h" +#include "../DarkMode.h" +#include "../Window.Win32.Context.h" LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { switch (uMsg) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowState.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowState.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp index 86d733134..eb590caaf 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowState.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp @@ -1,8 +1,8 @@ -#include "Window.Win32.Internal.h" +#include "../Window.Win32.Internal.h" #include -#include "Utils/Common.h" +#include "../../../Utils/Common.h" void InfiniFrameWindow::Center() { int screenDpi = GetDpiForWindow(m_impl->_hWnd); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowStorage.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp similarity index 96% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowStorage.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp index 4216d1002..f1d31bb75 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowStorage.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp @@ -1,7 +1,7 @@ #include #include -#include "Window.Win32.Context.h" +#include "../Window.Win32.Context.h" bool EnsureDirectoryWritable(const std::wstring& directoryPath) { if (directoryPath.empty()) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowTracing.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp similarity index 96% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowTracing.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp index 9c0f5e061..b4fb2efe5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WindowTracing.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp @@ -3,7 +3,7 @@ #include #include -#include "Window.Win32.Context.h" +#include "../Window.Win32.Context.h" bool IsTeardownTraceEnabled() { static const bool enabled = [] { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Attach.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Attach.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp index 67b1c5d5c..632225f16 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Attach.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp @@ -3,8 +3,8 @@ #include -#include "Embedded/Embedded.h" -#include "Window.Win32.Context.h" +#include "../../../Embedded/Embedded.h" +#include "../Window.Win32.Context.h" using namespace Microsoft::WRL; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Controller.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Controller.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp index f9250f692..5f137413d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Controller.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp @@ -1,4 +1,4 @@ -#include "Window.Win32.Context.h" +#include "../Window.Win32.Context.h" using namespace Microsoft::WRL; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp index 59b2633cc..95cb7ed6e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Host.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp @@ -1,4 +1,4 @@ -#include "Window.Win32.Context.h" +#include "../Window.Win32.Context.h" void InfiniFrameWindow::CloseWebView() { m_impl->_isClosingOrClosed.store(true, std::memory_order_release); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Runtime.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Runtime.Win32.cpp rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp index c32bc5acc..3dda10a56 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView2Runtime.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp @@ -1,6 +1,6 @@ #include -#include "Window.Win32.Context.h" +#include "../Window.Win32.Context.h" #pragma comment(lib, "Urlmon.lib") From 43931b2070d6d0631b2aa5a9549e1ba952acf1dc Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 19:17:18 +0200 Subject: [PATCH 07/86] Modularize macOS WebKit implementations and move shared export utilities to a dedicated folder. Update CMake and include paths accordingly. --- src/InfiniFrame.NativeBridge/Native/CMakeLists.txt | 9 +++++---- src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp | 2 +- .../Native/Exports/Exports.Dialog.cpp | 2 +- .../Native/Exports/Exports.Events.cpp | 2 +- .../Native/Exports/Exports.Lifecycle.cpp | 2 +- .../Native/Exports/Exports.Memory.cpp | 2 +- .../Native/Exports/Exports.Platform.cpp | 2 +- .../Native/Exports/Exports.WindowCommands.cpp | 2 +- .../Native/Exports/Exports.WindowState.cpp | 2 +- .../WebKitBridge.Cocoa.mm} | 0 .../WebKitCustomSchemes.Cocoa.mm} | 0 .../WebKitHost.Cocoa.mm} | 0 .../Native/{Exports => Utils}/ExportGuards.h | 0 .../Native/{Exports => Utils}/Exports.Shared.h | 0 14 files changed, 13 insertions(+), 12 deletions(-) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{WK/WKWebViewBridge.Cocoa.mm => WebKit/WebKitBridge.Cocoa.mm} (100%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{WK/WKCustomSchemes.Cocoa.mm => WebKit/WebKitCustomSchemes.Cocoa.mm} (100%) rename src/InfiniFrame.NativeBridge/Native/Platform/Mac/{WK/WKWebViewHost.Cocoa.mm => WebKit/WebKitHost.Cocoa.mm} (100%) rename src/InfiniFrame.NativeBridge/Native/{Exports => Utils}/ExportGuards.h (100%) rename src/InfiniFrame.NativeBridge/Native/{Exports => Utils}/Exports.Shared.h (100%) diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index a20591d47..22565b88c 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -91,9 +91,9 @@ set(MAC_SOURCES Platform/Mac/Core/WindowState.Cocoa.mm Platform/Mac/Core/WindowEvents.Cocoa.mm Platform/Mac/Core/UiDispatcher.Cocoa.mm - Platform/Mac/WK/WKWebViewBridge.Cocoa.mm - Platform/Mac/WK/WKCustomSchemes.Cocoa.mm - Platform/Mac/WK/WKWebViewHost.Cocoa.mm + Platform/Mac/WebKit/WebKitBridge.Cocoa.mm + Platform/Mac/WebKit/WebKitCustomSchemes.Cocoa.mm + Platform/Mac/WebKit/WebKitHost.Cocoa.mm ) set(HEADER_FILES @@ -108,7 +108,8 @@ set(HEADER_FILES Types/Callbacks.h Utils/Common.h Utils/Event.h - Exports/Exports.Shared.h + Utils/Exports.Shared.h + Utils/ExportGuards.h Platform/Windows/ToastHandler.h Platform/Windows/Window.Win32.Internal.h Platform/Windows/Window.Win32.Context.h diff --git a/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp index ce29df950..f70445794 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp @@ -1,5 +1,5 @@ #include "Core/InfiniFrame.h" -#include "Exports/ExportGuards.h" +#include "Utils/ExportGuards.h" #ifdef _WIN32 #define EXPORTED __declspec(dllexport) diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp index 58f3a7906..0bde8e061 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp @@ -1,4 +1,4 @@ -#include "Exports/Exports.Shared.h" +#include "Utils/Exports.Shared.h" extern "C" { EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, AutoString* filters, const int filterCount, int* resultCount, AutoString** values) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp index fdbebd787..fecc78c23 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp @@ -1,4 +1,4 @@ -#include "Exports/Exports.Shared.h" +#include "Utils/Exports.Shared.h" extern "C" { EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp index e66c096b7..cb9d00d95 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp @@ -1,4 +1,4 @@ -#include "Exports/Exports.Shared.h" +#include "Utils/Exports.Shared.h" extern "C" { EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp index 17a8fafab..fcf7eeb6e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp @@ -1,4 +1,4 @@ -#include "Exports/Exports.Shared.h" +#include "Utils/Exports.Shared.h" extern "C" { EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp index a1c4a6070..318fb7bb3 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp @@ -1,4 +1,4 @@ -#include "Exports/Exports.Shared.h" +#include "Utils/Exports.Shared.h" extern "C" { #ifdef _WIN32 diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp index 7548826c9..b73ada68d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp @@ -1,4 +1,4 @@ -#include "Exports/Exports.Shared.h" +#include "Utils/Exports.Shared.h" extern "C" { EXPORTED InteropStatus InfiniFrame_Center(InfiniFrameWindow* instance) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp index a4d81e8fc..42852cd65 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp @@ -1,4 +1,4 @@ -#include "Exports/Exports.Shared.h" +#include "Utils/Exports.Shared.h" extern "C" { EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewBridge.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitBridge.Cocoa.mm similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewBridge.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitBridge.Cocoa.mm diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKCustomSchemes.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitCustomSchemes.Cocoa.mm similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKCustomSchemes.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitCustomSchemes.Cocoa.mm diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewHost.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitHost.Cocoa.mm similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Platform/Mac/WK/WKWebViewHost.Cocoa.mm rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitHost.Cocoa.mm diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Exports/ExportGuards.h rename to src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Shared.h b/src/InfiniFrame.NativeBridge/Native/Utils/Exports.Shared.h similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.Shared.h rename to src/InfiniFrame.NativeBridge/Native/Utils/Exports.Shared.h From 93f32c4c69dbdb89356b2a35eacaf1d377c7b218 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 19:20:28 +0200 Subject: [PATCH 08/86] Remove `Exports.Shared.h` and consolidate exports into the new `Core/Exports.h`. Update include paths and CMake references accordingly. --- src/InfiniFrame.NativeBridge/Native/CMakeLists.txt | 4 ++-- .../Native/{Utils/Exports.Shared.h => Core/Exports.h} | 10 +++++----- .../Native/Exports/Exports.Dialog.cpp | 2 +- .../Native/Exports/Exports.Events.cpp | 2 +- .../Native/Exports/Exports.Lifecycle.cpp | 2 +- .../Native/Exports/Exports.Memory.cpp | 2 +- .../Native/Exports/Exports.Platform.cpp | 2 +- .../Native/{ => Exports}/Exports.Tests.cpp | 0 .../Native/Exports/Exports.WindowCommands.cpp | 2 +- .../Native/Exports/Exports.WindowState.cpp | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) rename src/InfiniFrame.NativeBridge/Native/{Utils/Exports.Shared.h => Core/Exports.h} (74%) rename src/InfiniFrame.NativeBridge/Native/{ => Exports}/Exports.Tests.cpp (100%) diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index 22565b88c..2abed9233 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -41,7 +41,7 @@ set(COMMON_SOURCES ) set(TEST_SOURCES - Exports.Tests.cpp + Exports/Exports.Tests.cpp ) set(WINDOWS_SOURCES @@ -108,7 +108,7 @@ set(HEADER_FILES Types/Callbacks.h Utils/Common.h Utils/Event.h - Utils/Exports.Shared.h + Core/Exports.h Utils/ExportGuards.h Platform/Windows/ToastHandler.h Platform/Windows/Window.Win32.Internal.h diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Exports.Shared.h b/src/InfiniFrame.NativeBridge/Native/Core/Exports.h similarity index 74% rename from src/InfiniFrame.NativeBridge/Native/Utils/Exports.Shared.h rename to src/InfiniFrame.NativeBridge/Native/Core/Exports.h index fa1d75ee5..fba8bacc6 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Exports.Shared.h +++ b/src/InfiniFrame.NativeBridge/Native/Core/Exports.h @@ -1,10 +1,10 @@ #pragma once -#ifndef INFINIFRAME_EXPORTS_SHARED_H -#define INFINIFRAME_EXPORTS_SHARED_H +#ifndef INFINIFRAME_CORE_EXPORTS_H +#define INFINIFRAME_CORE_EXPORTS_H -#include "../Core/InfiniFrame.h" -#include "ExportGuards.h" +#include "InfiniFrame.h" +#include "../Utils/ExportGuards.h" #ifdef __linux__ #include @@ -25,4 +25,4 @@ using infiniframe::exports::RunReturnExport; using infiniframe::exports::RunWindowExportStatus; using infiniframe::exports::RunWindowReturnExport; -#endif // INFINIFRAME_EXPORTS_SHARED_H +#endif // INFINIFRAME_CORE_EXPORTS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp index 0bde8e061..881470e48 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp @@ -1,4 +1,4 @@ -#include "Utils/Exports.Shared.h" +#include "Core/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, AutoString* filters, const int filterCount, int* resultCount, AutoString** values) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp index fecc78c23..aff16e34e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp @@ -1,4 +1,4 @@ -#include "Utils/Exports.Shared.h" +#include "Core/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp index cb9d00d95..4592847ed 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp @@ -1,4 +1,4 @@ -#include "Utils/Exports.Shared.h" +#include "Core/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp index fcf7eeb6e..70f12ff6f 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp @@ -1,4 +1,4 @@ -#include "Utils/Exports.Shared.h" +#include "Core/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp index 318fb7bb3..fe42bab9d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp @@ -1,4 +1,4 @@ -#include "Utils/Exports.Shared.h" +#include "Core/Exports.h" extern "C" { #ifdef _WIN32 diff --git a/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Tests.cpp similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp rename to src/InfiniFrame.NativeBridge/Native/Exports/Exports.Tests.cpp diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp index b73ada68d..f5154658f 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp @@ -1,4 +1,4 @@ -#include "Utils/Exports.Shared.h" +#include "Core/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_Center(InfiniFrameWindow* instance) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp index 42852cd65..2eb4695c6 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp @@ -1,4 +1,4 @@ -#include "Utils/Exports.Shared.h" +#include "Core/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { From bad7c10eaafe09630102be6a02ac9a049ec771ca Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 19:43:47 +0200 Subject: [PATCH 09/86] Remove `Native/Exports` source files and consolidate NativeBridge export logic into shared core. Update references and CMake configurations accordingly. --- .../Native/CMakeLists.txt | 37 ++-- .../Linux/Core/WindowInitialization.Gtk.cpp | 2 +- .../Native/Platform/Linux/Dialog.cpp | 2 +- .../Platform/Linux/Window.Gtk.Internal.h | 4 +- .../Platform/Mac/Core/WindowCore.Cocoa.mm | 4 +- .../Native/Platform/Mac/Dialog.mm | 2 +- .../Native/Platform/Mac/NSWindowBorderless.h | 2 +- .../Native/Platform/Mac/NavigationDelegate.h | 2 +- .../Native/Platform/Mac/UiDelegate.h | 2 +- .../Native/Platform/Mac/UrlSchemeHandler.h | 2 +- .../Platform/Mac/Window.Cocoa.Internal.h | 4 +- .../Native/Platform/Mac/WindowDelegate.h | 2 +- .../Native/Platform/Windows/Dialog.cpp | 2 +- .../Native/Platform/Windows/ToastHandler.h | 2 +- .../Platform/Windows/Window.Win32.Context.h | 2 +- .../Platform/Windows/Window.Win32.Internal.h | 4 +- .../{ => Public}/Exports/Exports.Dialog.cpp | 2 +- .../{ => Public}/Exports/Exports.Events.cpp | 2 +- .../Exports/Exports.Lifecycle.cpp | 2 +- .../{ => Public}/Exports/Exports.Memory.cpp | 2 +- .../{ => Public}/Exports/Exports.Platform.cpp | 2 +- .../{ => Public}/Exports/Exports.Tests.cpp | 2 +- .../Exports/Exports.WindowCommands.cpp | 2 +- .../Exports/Exports.WindowState.cpp | 2 +- .../Native/{Core => Public/Exports}/Exports.h | 10 +- .../Native/{Core => Public}/InfiniFrame.h | 0 .../{Core => Public}/InfiniFrameDialog.h | 0 .../{Core => Public}/InfiniFrameInitParams.h | 0 .../{Core => Public}/InfiniFrameWindow.h | 0 .../{Core => Public}/InfiniFrameWindowImpl.h | 0 .../Native/Types/Dialog.h | 59 +----- .../Native/Types/DialogButtons.h | 15 ++ .../Native/Types/DialogIcon.h | 13 ++ .../Native/Types/DialogResult.h | 16 ++ .../Native/Types/Monitor.h | 15 ++ .../Native/Utils/Common.h | 182 +----------------- .../Native/Utils/Dimensions.h | 18 ++ .../Native/Utils/ErrorCode.h | 75 ++++++++ .../Native/Utils/ExportGuards.h | 2 +- .../Native/Utils/Result.h | 13 ++ .../Native/Utils/StringCopy.h | 44 +++++ .../Native/Utils/WindowsHandles.h | 38 ++++ 42 files changed, 313 insertions(+), 278 deletions(-) rename src/InfiniFrame.NativeBridge/Native/{ => Public}/Exports/Exports.Dialog.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/{ => Public}/Exports/Exports.Events.cpp (98%) rename src/InfiniFrame.NativeBridge/Native/{ => Public}/Exports/Exports.Lifecycle.cpp (97%) rename src/InfiniFrame.NativeBridge/Native/{ => Public}/Exports/Exports.Memory.cpp (97%) rename src/InfiniFrame.NativeBridge/Native/{ => Public}/Exports/Exports.Platform.cpp (97%) rename src/InfiniFrame.NativeBridge/Native/{ => Public}/Exports/Exports.Tests.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/{ => Public}/Exports/Exports.WindowCommands.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/{ => Public}/Exports/Exports.WindowState.cpp (99%) rename src/InfiniFrame.NativeBridge/Native/{Core => Public/Exports}/Exports.h (73%) rename src/InfiniFrame.NativeBridge/Native/{Core => Public}/InfiniFrame.h (100%) rename src/InfiniFrame.NativeBridge/Native/{Core => Public}/InfiniFrameDialog.h (100%) rename src/InfiniFrame.NativeBridge/Native/{Core => Public}/InfiniFrameInitParams.h (100%) rename src/InfiniFrame.NativeBridge/Native/{Core => Public}/InfiniFrameWindow.h (100%) rename src/InfiniFrame.NativeBridge/Native/{Core => Public}/InfiniFrameWindowImpl.h (100%) create mode 100644 src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Types/Monitor.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Utils/Result.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h create mode 100644 src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index 2abed9233..817a9fd3d 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 4.0) +cmake_minimum_required(VERSION 4.0) project(InfiniFrame.Native VERSION 1.1.1 LANGUAGES CXX @@ -31,17 +31,17 @@ infiniframe_setup_dependencies() # Source Files # ---------------------------------------------------------------------------------------------------------------------- set(COMMON_SOURCES - Exports/Exports.Platform.cpp - Exports/Exports.Lifecycle.cpp - Exports/Exports.WindowState.cpp - Exports/Exports.WindowCommands.cpp - Exports/Exports.Dialog.cpp - Exports/Exports.Events.cpp - Exports/Exports.Memory.cpp + Public/Exports/Exports.Platform.cpp + Public/Exports/Exports.Lifecycle.cpp + Public/Exports/Exports.WindowState.cpp + Public/Exports/Exports.WindowCommands.cpp + Public/Exports/Exports.Dialog.cpp + Public/Exports/Exports.Events.cpp + Public/Exports/Exports.Memory.cpp ) set(TEST_SOURCES - Exports/Exports.Tests.cpp + Public/Exports/Exports.Tests.cpp ) set(WINDOWS_SOURCES @@ -97,18 +97,27 @@ set(MAC_SOURCES ) set(HEADER_FILES - Core/InfiniFrame.h - Core/InfiniFrameWindow.h - Core/InfiniFrameDialog.h + Public/InfiniFrame.h + Public/InfiniFrameWindow.h + Public/InfiniFrameDialog.h Embedded/Embedded.h Embedded/InfiniFrameJs/InfiniFrameJs.h Types/Basic.h Types/Dialog.h - Core/InfiniFrameInitParams.h + Types/DialogResult.h + Types/DialogButtons.h + Types/DialogIcon.h + Types/Monitor.h + Public/InfiniFrameInitParams.h Types/Callbacks.h Utils/Common.h + Utils/Dimensions.h + Utils/ErrorCode.h + Utils/Result.h + Utils/StringCopy.h + Utils/WindowsHandles.h Utils/Event.h - Core/Exports.h + Public/Exports/Exports.h Utils/ExportGuards.h Platform/Windows/ToastHandler.h Platform/Windows/Window.Win32.Internal.h diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp index ccd4a63e7..9e1bb3288 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp @@ -2,7 +2,7 @@ #include -#include "../../../Core/InfiniFrameDialog.h" +#include "../../../Public/InfiniFrameDialog.h" #include "../Window.Gtk.Internal.h" gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, gpointer self); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp index 43b1c0d9c..37a65a0dc 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp @@ -4,7 +4,7 @@ * @brief Linux implementation of InfiniFrameDialog using GTK3 file-chooser and message dialogs */ -#include "Core/InfiniFrameDialog.h" +#include "Public/InfiniFrameDialog.h" #include /** @brief Distinguishes which GtkFileChooserAction to configure in ShowDialog */ diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h index e708906da..0d7d9142e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h @@ -9,8 +9,8 @@ #include #include -#include "Core/InfiniFrameWindow.h" -#include "Core/InfiniFrameWindowImpl.h" +#include "Public/InfiniFrameWindow.h" +#include "Public/InfiniFrameWindowImpl.h" struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { GtkWidget* _window = nullptr; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowCore.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowCore.Cocoa.mm index 03703eed7..b5a5e569f 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowCore.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowCore.Cocoa.mm @@ -3,8 +3,8 @@ #include #include "../AppDelegate.h" -#include "../../../Core/InfiniFrameDialog.h" -#include "../../../Core/InfiniFrameWindow.h" +#include "../../../Public/InfiniFrameDialog.h" +#include "../../../Public/InfiniFrameWindow.h" #include "../NSWindowBorderless.h" #include "../Window.Cocoa.Internal.h" #include "../WindowDelegate.h" diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Dialog.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Dialog.mm index 80144d07b..09ac5845b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Dialog.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Dialog.mm @@ -4,7 +4,7 @@ * @brief macOS implementation of InfiniFrameDialog using NSOpenPanel, NSSavePanel, and NSAlert */ -#import "Core/InfiniFrameDialog.h" +#import "Public/InfiniFrameDialog.h" #if defined(VSTGUI_USE_OBJC_UTTYPE) #import diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NSWindowBorderless.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NSWindowBorderless.h index fae41e0bb..4aebdb279 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NSWindowBorderless.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NSWindowBorderless.h @@ -7,7 +7,7 @@ * Used when InfiniFrameInitParams::Transparent is set, allowing the WebView to render * over a fully transparent window background without the standard title bar and borders */ -#include "Core/InfiniFrame.h" +#include "Public/InfiniFrame.h" /** * @brief Borderless, transparent NSWindow subclass. diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NavigationDelegate.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NavigationDelegate.h index 2d638074e..d8ee80f75 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NavigationDelegate.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NavigationDelegate.h @@ -4,7 +4,7 @@ * @file NavigationDelegate.h * @brief WKNavigationDelegate that handles TLS certificate validation for the embedded WebView */ -#include "Core/InfiniFrame.h" +#include "Public/InfiniFrame.h" /** * @brief Navigation delegate conforming to WKNavigationDelegate. diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.h index 3941068c1..1c5768891 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.h @@ -4,7 +4,7 @@ * @file UiDelegate.h * @brief WKUIDelegate and WKScriptMessageHandler that routes JavaScript messages to the .NET layer */ -#include "Core/InfiniFrame.h" +#include "Public/InfiniFrame.h" /** * @brief UI delegate conforming to WKUIDelegate and WKScriptMessageHandler. diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UrlSchemeHandler.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UrlSchemeHandler.h index 9d5f201f0..0639b7600 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UrlSchemeHandler.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UrlSchemeHandler.h @@ -4,7 +4,7 @@ * @file UrlSchemeHandler.h * @brief WKURLSchemeHandler that intercepts custom-scheme requests and serves responses from the .NET layer */ -#include "Core/InfiniFrame.h" +#include "Public/InfiniFrame.h" /** * @brief URL scheme handler conforming to WKURLSchemeHandler. diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h index 0a78c38fa..86d05f383 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h @@ -9,8 +9,8 @@ #include #include -#include "Core/InfiniFrameWindow.h" -#include "Core/InfiniFrameWindowImpl.h" +#include "Public/InfiniFrameWindow.h" +#include "Public/InfiniFrameWindowImpl.h" struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { NSWindow* _window = nil; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowDelegate.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowDelegate.h index d9c42685b..93f3c0729 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowDelegate.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowDelegate.h @@ -4,7 +4,7 @@ * @file WindowDelegate.h * @brief NSWindow delegate that forwards window lifecycle events to InfiniFrameWindow callbacks */ -#include "Core/InfiniFrame.h" +#include "Public/InfiniFrame.h" /** * @brief Per-window delegate conforming to NSWindowDelegate. diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp index 6a9d481dd..2467ce3ca 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp @@ -3,7 +3,7 @@ * @brief Windows implementation of InfiniFrameDialog using IFileDialog (Vista+) and MessageBoxW */ -#include "Core/InfiniFrame.h" +#include "Public/InfiniFrame.h" #include #include diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h index 7b8c2afff..578b0f206 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h @@ -5,7 +5,7 @@ */ #include -#include "Core/InfiniFrameWindow.h" +#include "Public/InfiniFrameWindow.h" #include "Dependencies/wintoastlib/wintoastlib.h" using namespace WinToastLib; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h index 859f5f316..a3741e81a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h @@ -10,7 +10,7 @@ #include -#include "Core/InfiniFrameWindow.h" +#include "Public/InfiniFrameWindow.h" #include "Window.Win32.Internal.h" inline constexpr UINT WM_USER_INVOKE = WM_USER + 0x0002; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h index 684519507..3702fbf47 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h @@ -10,8 +10,8 @@ #include #include -#include "Core/InfiniFrameWindow.h" -#include "Core/InfiniFrameWindowImpl.h" +#include "Public/InfiniFrameWindow.h" +#include "Public/InfiniFrameWindowImpl.h" #include "ToastHandler.h" #include "Utils/Common.h" diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp index 881470e48..50effa5a5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp @@ -1,4 +1,4 @@ -#include "Core/Exports.h" +#include "Public/Exports/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, AutoString* filters, const int filterCount, int* resultCount, AutoString** values) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp similarity index 98% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp index aff16e34e..706bd670e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Events.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp @@ -1,4 +1,4 @@ -#include "Core/Exports.h" +#include "Public/Exports/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp index 4592847ed..915367249 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Lifecycle.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp @@ -1,4 +1,4 @@ -#include "Core/Exports.h" +#include "Public/Exports/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp index 70f12ff6f..7b207555f 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Memory.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp @@ -1,4 +1,4 @@ -#include "Core/Exports.h" +#include "Public/Exports/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp similarity index 97% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp index fe42bab9d..89caed16c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Platform.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp @@ -1,4 +1,4 @@ -#include "Core/Exports.h" +#include "Public/Exports/Exports.h" extern "C" { #ifdef _WIN32 diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.Tests.cpp rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp index f70445794..51b5010da 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.Tests.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp @@ -1,4 +1,4 @@ -#include "Core/InfiniFrame.h" +#include "Public/InfiniFrame.h" #include "Utils/ExportGuards.h" #ifdef _WIN32 diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp index f5154658f..244e0b6ef 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowCommands.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp @@ -1,4 +1,4 @@ -#include "Core/Exports.h" +#include "Public/Exports/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_Center(InfiniFrameWindow* instance) { diff --git a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp similarity index 99% rename from src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp index 2eb4695c6..2b8812099 100644 --- a/src/InfiniFrame.NativeBridge/Native/Exports/Exports.WindowState.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp @@ -1,4 +1,4 @@ -#include "Core/Exports.h" +#include "Public/Exports/Exports.h" extern "C" { EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { diff --git a/src/InfiniFrame.NativeBridge/Native/Core/Exports.h b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h similarity index 73% rename from src/InfiniFrame.NativeBridge/Native/Core/Exports.h rename to src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h index fba8bacc6..c5f531aff 100644 --- a/src/InfiniFrame.NativeBridge/Native/Core/Exports.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h @@ -1,10 +1,10 @@ #pragma once -#ifndef INFINIFRAME_CORE_EXPORTS_H -#define INFINIFRAME_CORE_EXPORTS_H +#ifndef INFINIFRAME_PUBLIC_EXPORTS_H +#define INFINIFRAME_PUBLIC_EXPORTS_H -#include "InfiniFrame.h" -#include "../Utils/ExportGuards.h" +#include "../InfiniFrame.h" +#include "../../Utils/ExportGuards.h" #ifdef __linux__ #include @@ -25,4 +25,4 @@ using infiniframe::exports::RunReturnExport; using infiniframe::exports::RunWindowExportStatus; using infiniframe::exports::RunWindowReturnExport; -#endif // INFINIFRAME_CORE_EXPORTS_H +#endif // INFINIFRAME_PUBLIC_EXPORTS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrame.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Core/InfiniFrame.h rename to src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h diff --git a/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameDialog.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameDialog.h rename to src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h diff --git a/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameInitParams.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameInitParams.h rename to src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h diff --git a/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameWindow.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameWindow.h rename to src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h diff --git a/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameWindowImpl.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h similarity index 100% rename from src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameWindowImpl.h rename to src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h b/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h index 690088813..450081abb 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h @@ -7,60 +7,9 @@ #ifndef INFINIFRAME_TYPES_DIALOG_H #define INFINIFRAME_TYPES_DIALOG_H -// --------------------------------------------------------------------------------------------------------------------- -// Dialog Result -// --------------------------------------------------------------------------------------------------------------------- - -/** @brief Button pressed by the user to dismiss a message box */ -enum class DialogResult { - Cancel = -1, /// Dialog was cancelled (Escape key or window close) - Ok, /// User pressed OK - Yes, /// User pressed Yes - No, /// User pressed No - Abort, /// User pressed Abort - Retry, /// User pressed Retry - Ignore, /// User pressed Ignore -}; - -// --------------------------------------------------------------------------------------------------------------------- -// Dialog Buttons -// --------------------------------------------------------------------------------------------------------------------- - -/** @brief Button set to display in a message box */ -enum class DialogButtons { - Ok, /// Single OK button - OkCancel, /// OK and Cancel buttons - YesNo, /// Yes and No buttons - YesNoCancel, /// Yes, No, and Cancel buttons - RetryCancel, /// Retry and Cancel buttons - AbortRetryIgnore, /// Abort, Retry, and Ignore buttons -}; - -// --------------------------------------------------------------------------------------------------------------------- -// Dialog Icon -// --------------------------------------------------------------------------------------------------------------------- - -/** @brief Icon shown in a message box */ -enum class DialogIcon { - Info, - Warning, - Error, - Question, -}; - -// --------------------------------------------------------------------------------------------------------------------- -// Monitor -// --------------------------------------------------------------------------------------------------------------------- - -/** @brief Describes the geometry of a single display */ -struct Monitor { - /** @brief Pixel rectangle relative to the virtual desktop */ - struct MonitorRect { - int x, y; /// Top-left corner in virtual-desktop coordinates - int width, height; /// Dimensions in physical pixels - } monitor, /// Full monitor bounds (including taskbar) - work; /// Work area bounds (excluding taskbar and docked toolbars) - double scale; /// DPI scale factor (1.0 = 100%, 1.5 = 150%) -}; +#include "DialogButtons.h" +#include "DialogIcon.h" +#include "DialogResult.h" +#include "Monitor.h" #endif // INFINIFRAME_TYPES_DIALOG_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h new file mode 100644 index 000000000..5c7ea86d2 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h @@ -0,0 +1,15 @@ +#pragma once + +#ifndef INFINIFRAME_TYPES_DIALOG_BUTTONS_H +#define INFINIFRAME_TYPES_DIALOG_BUTTONS_H + +enum class DialogButtons { + Ok, + OkCancel, + YesNo, + YesNoCancel, + RetryCancel, + AbortRetryIgnore, +}; + +#endif // INFINIFRAME_TYPES_DIALOG_BUTTONS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h new file mode 100644 index 000000000..928b1bd66 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h @@ -0,0 +1,13 @@ +#pragma once + +#ifndef INFINIFRAME_TYPES_DIALOG_ICON_H +#define INFINIFRAME_TYPES_DIALOG_ICON_H + +enum class DialogIcon { + Info, + Warning, + Error, + Question, +}; + +#endif // INFINIFRAME_TYPES_DIALOG_ICON_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h new file mode 100644 index 000000000..10065db08 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h @@ -0,0 +1,16 @@ +#pragma once + +#ifndef INFINIFRAME_TYPES_DIALOG_RESULT_H +#define INFINIFRAME_TYPES_DIALOG_RESULT_H + +enum class DialogResult { + Cancel = -1, + Ok, + Yes, + No, + Abort, + Retry, + Ignore, +}; + +#endif // INFINIFRAME_TYPES_DIALOG_RESULT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h b/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h new file mode 100644 index 000000000..570e78ac5 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h @@ -0,0 +1,15 @@ +#pragma once + +#ifndef INFINIFRAME_TYPES_MONITOR_H +#define INFINIFRAME_TYPES_MONITOR_H + +struct Monitor { + struct MonitorRect { + int x, y; + int width, height; + } monitor, + work; + double scale; +}; + +#endif // INFINIFRAME_TYPES_MONITOR_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Common.h b/src/InfiniFrame.NativeBridge/Native/Utils/Common.h index f01864e51..82f92f806 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Common.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Common.h @@ -1,186 +1,16 @@ #pragma once /** * @file Common.h - * @brief Common utilities for cross-platform development + * @brief Compatibility umbrella for common utilities */ #ifndef INFINIFRAME_COMMON_H #define INFINIFRAME_COMMON_H -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -// --------------------------------------------------------------------------------------------------------------------- -// Constants -// --------------------------------------------------------------------------------------------------------------------- - -inline constexpr int MaxWindowDimension = 10000; -inline constexpr int MinWindowDimension = 50; -inline constexpr int DefaultWindowWidth = 800; -inline constexpr int DefaultWindowHeight = 600; - -// --------------------------------------------------------------------------------------------------------------------- -// Error Codes -// --------------------------------------------------------------------------------------------------------------------- - -enum class ErrorCode { - Success = 0, - InvalidArgument, - NotInitialized, - PlatformNotSupported, - WebViewError, - EncodingError, - MemoryError, - IoError, - NullPointer, - InterfaceNotAvailable, - PropertyAccessFailed, - WindowNotFound -}; - -// --------------------------------------------------------------------------------------------------------------------- -// Error Category -// --------------------------------------------------------------------------------------------------------------------- - -inline const std::error_category& errorCategory() noexcept { - struct InfiniFrameCategory : std::error_category { - const char*name() const noexcept override { - return "InfiniFrame"; - } - - std::string message(int ev) const override { - switch (static_cast(ev)) { - case ErrorCode::Success: - return "Success"; - case ErrorCode::InvalidArgument: - return "Invalid argument"; - case ErrorCode::NotInitialized: - return "Not initialized"; - case ErrorCode::PlatformNotSupported: - return "Platform not supported"; - case ErrorCode::WebViewError: - return "WebView error"; - case ErrorCode::EncodingError: - return "Encoding error"; - case ErrorCode::MemoryError: - return "Memory error"; - case ErrorCode::IoError: - return "I/O error"; - case ErrorCode::NullPointer: - return "Null pointer"; - case ErrorCode::InterfaceNotAvailable: - return "Interface not available"; - case ErrorCode::PropertyAccessFailed: - return "Property access failed"; - case ErrorCode::WindowNotFound: - return "Window not found"; - default: - return "Unknown error"; - } - } - }; - static const InfiniFrameCategory category; - return category; -} - -inline std::error_code make_error_code(ErrorCode e) noexcept { - return {static_cast(e), errorCategory()}; -} - -namespace std { - template <> - struct is_error_code_enum : true_type { - }; -} - -// --------------------------------------------------------------------------------------------------------------------- -// Result Type -// --------------------------------------------------------------------------------------------------------------------- - -template -using Result = std::expected; - -// --------------------------------------------------------------------------------------------------------------------- -// RAII Wrappers (Windows) -// --------------------------------------------------------------------------------------------------------------------- - -#ifdef _WIN32 - -struct HBRUSHDeleter { - void operator()(void* h) const noexcept { - if (h) - DeleteObject(static_cast(h)); - } -}; - -struct HICONDeleter { - void operator()(void* h) const noexcept { - if (h) - DestroyIcon(static_cast(h)); - } -}; - -struct HDCDeleter { - void operator()(void* h) const noexcept { - if (h) - DeleteDC(static_cast(h)); - } -}; - -using UniqueHBRUSH = std::unique_ptr; -using UniqueHICON = std::unique_ptr; -using UniqueHDC = std::unique_ptr; - -#endif - -// --------------------------------------------------------------------------------------------------------------------- -// Helper Functions -// --------------------------------------------------------------------------------------------------------------------- - -template -[[nodiscard]] constexpr T clampDimension(T value, T minVal = MinWindowDimension, T maxVal = MaxWindowDimension) { - return std::clamp(value, minVal, maxVal); -} - -#ifdef _WIN32 -inline wchar_t* AllocateStringCopy(const std::wstring& str) { - const size_t len = str.length(); - wchar_t* copy = new wchar_t[len + 1]; - std::memcpy(copy, str.c_str(), (len + 1) * sizeof(wchar_t)); - return copy; -} - -#elif __linux__ -inline char* AllocateStringCopy(const std::string& str) { - return g_strdup(str.c_str()); -} - -#elif __APPLE__ -inline char* AllocateStringCopy(const std::string& str) { - const size_t len = str.length(); - char* copy = static_cast(malloc(len + 1)); - std::memcpy(copy, str.c_str(), len + 1); - return copy; -} - -#else -inline char* AllocateStringCopy(const std::string& str) { - const size_t len = str.length(); - char* copy = static_cast(malloc(len + 1)); - std::memcpy(copy, str.c_str(), len + 1); - return copy; -} -#endif +#include "Dimensions.h" +#include "ErrorCode.h" +#include "Result.h" +#include "StringCopy.h" +#include "WindowsHandles.h" #endif // INFINIFRAME_COMMON_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h b/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h new file mode 100644 index 000000000..0feca8da7 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h @@ -0,0 +1,18 @@ +#pragma once + +#ifndef INFINIFRAME_UTILS_DIMENSIONS_H +#define INFINIFRAME_UTILS_DIMENSIONS_H + +#include + +inline constexpr int MaxWindowDimension = 10000; +inline constexpr int MinWindowDimension = 50; +inline constexpr int DefaultWindowWidth = 800; +inline constexpr int DefaultWindowHeight = 600; + +template +[[nodiscard]] constexpr T clampDimension(T value, T minVal = MinWindowDimension, T maxVal = MaxWindowDimension) { + return std::clamp(value, minVal, maxVal); +} + +#endif // INFINIFRAME_UTILS_DIMENSIONS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h new file mode 100644 index 000000000..3c43e0f08 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h @@ -0,0 +1,75 @@ +#pragma once + +#ifndef INFINIFRAME_UTILS_ERROR_CODE_H +#define INFINIFRAME_UTILS_ERROR_CODE_H + +#include +#include + +enum class ErrorCode { + Success = 0, + InvalidArgument, + NotInitialized, + PlatformNotSupported, + WebViewError, + EncodingError, + MemoryError, + IoError, + NullPointer, + InterfaceNotAvailable, + PropertyAccessFailed, + WindowNotFound +}; + +inline const std::error_category& errorCategory() noexcept { + struct InfiniFrameCategory : std::error_category { + const char*name() const noexcept override { + return "InfiniFrame"; + } + + std::string message(int ev) const override { + switch (static_cast(ev)) { + case ErrorCode::Success: + return "Success"; + case ErrorCode::InvalidArgument: + return "Invalid argument"; + case ErrorCode::NotInitialized: + return "Not initialized"; + case ErrorCode::PlatformNotSupported: + return "Platform not supported"; + case ErrorCode::WebViewError: + return "WebView error"; + case ErrorCode::EncodingError: + return "Encoding error"; + case ErrorCode::MemoryError: + return "Memory error"; + case ErrorCode::IoError: + return "I/O error"; + case ErrorCode::NullPointer: + return "Null pointer"; + case ErrorCode::InterfaceNotAvailable: + return "Interface not available"; + case ErrorCode::PropertyAccessFailed: + return "Property access failed"; + case ErrorCode::WindowNotFound: + return "Window not found"; + default: + return "Unknown error"; + } + } + }; + static const InfiniFrameCategory category; + return category; +} + +inline std::error_code make_error_code(const ErrorCode e) noexcept { + return {static_cast(e), errorCategory()}; +} + +namespace std { + template <> + struct is_error_code_enum : true_type { + }; +} + +#endif // INFINIFRAME_UTILS_ERROR_CODE_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h index 4c41d3750..2fba3ae74 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h @@ -9,7 +9,7 @@ #include #include -#include "../Core/InfiniFrame.h" +#include "../Public/InfiniFrame.h" #ifdef _WIN32 #include diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Result.h b/src/InfiniFrame.NativeBridge/Native/Utils/Result.h new file mode 100644 index 000000000..3ddc38147 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Result.h @@ -0,0 +1,13 @@ +#pragma once + +#ifndef INFINIFRAME_UTILS_RESULT_H +#define INFINIFRAME_UTILS_RESULT_H + +#include + +#include "ErrorCode.h" + +template +using Result = std::expected; + +#endif // INFINIFRAME_UTILS_RESULT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h b/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h new file mode 100644 index 000000000..3f63fc2d2 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h @@ -0,0 +1,44 @@ +#pragma once + +#ifndef INFINIFRAME_UTILS_STRING_COPY_H +#define INFINIFRAME_UTILS_STRING_COPY_H + +#include +#include +#include + +#ifdef __linux__ +#include +#endif + +#ifdef _WIN32 +inline wchar_t* AllocateStringCopy(const std::wstring& str) { + const size_t len = str.length(); + wchar_t* copy = new wchar_t[len + 1]; + std::memcpy(copy, str.c_str(), (len + 1) * sizeof(wchar_t)); + return copy; +} + +#elif __linux__ +inline char* AllocateStringCopy(const std::string& str) { + return g_strdup(str.c_str()); +} + +#elif __APPLE__ +inline char* AllocateStringCopy(const std::string& str) { + const size_t len = str.length(); + char* copy = static_cast(malloc(len + 1)); + std::memcpy(copy, str.c_str(), len + 1); + return copy; +} + +#else +inline char* AllocateStringCopy(const std::string& str) { + const size_t len = str.length(); + char* copy = static_cast(malloc(len + 1)); + std::memcpy(copy, str.c_str(), len + 1); + return copy; +} +#endif + +#endif // INFINIFRAME_UTILS_STRING_COPY_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h b/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h new file mode 100644 index 000000000..5f5b0a74f --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h @@ -0,0 +1,38 @@ +#pragma once + +#ifndef INFINIFRAME_UTILS_WINDOWS_HANDLES_H +#define INFINIFRAME_UTILS_WINDOWS_HANDLES_H + +#ifdef _WIN32 + +#include +#include + +struct HBRUSHDeleter { + void operator()(void* h) const noexcept { + if (h) + DeleteObject(static_cast(h)); + } +}; + +struct HICONDeleter { + void operator()(void* h) const noexcept { + if (h) + DestroyIcon(static_cast(h)); + } +}; + +struct HDCDeleter { + void operator()(void* h) const noexcept { + if (h) + DeleteDC(static_cast(h)); + } +}; + +using UniqueHBRUSH = std::unique_ptr; +using UniqueHICON = std::unique_ptr; +using UniqueHDC = std::unique_ptr; + +#endif + +#endif // INFINIFRAME_UTILS_WINDOWS_HANDLES_H From ea8f5698b9367de6d6a2eafb61bfe173ca4c92dc Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 21:01:10 +0200 Subject: [PATCH 10/86] Refine frontend build logic for stale lock detection by introducing safer lock age calculations and improving error handling. --- scripts/BuildFrontend.mjs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/scripts/BuildFrontend.mjs b/scripts/BuildFrontend.mjs index 9e7207a31..d30625e6c 100644 --- a/scripts/BuildFrontend.mjs +++ b/scripts/BuildFrontend.mjs @@ -45,6 +45,22 @@ function isProcessRunning(processId) { function shouldRemoveExistingLock() { const ownerFile = path.join(lockDirectory, 'owner.txt'); const staleLockThresholdMilliseconds = 10 * 60 * 1000; + const lockAgeMilliseconds = (() => { + try { + return Date.now() - statSync(lockDirectory).mtimeMs; + } catch (error) { + if (error?.code === 'ENOENT') { + return null; + } + + throw error; + } + })(); + + // PIDs can be recycled by the OS. If the lock is old, remove it regardless of PID state. + if (lockAgeMilliseconds !== null && lockAgeMilliseconds > staleLockThresholdMilliseconds) { + return true; + } if (existsSync(ownerFile)) { const ownerProcessId = Number.parseInt(readFileSync(ownerFile, 'utf8'), 10); @@ -56,17 +72,7 @@ function shouldRemoveExistingLock() { return false; } } - - try { - const lockAgeMilliseconds = Date.now() - statSync(lockDirectory).mtimeMs; - return lockAgeMilliseconds > staleLockThresholdMilliseconds; - } catch (error) { - if (error?.code === 'ENOENT') { - return false; - } - - throw error; - } + return false; } function acquireLock() { From 641bdad21835944a10af9798d9753e009ad94199 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 21:02:49 +0200 Subject: [PATCH 11/86] Add `enable_test_exports` option to workflows and native build scripts for flexible export configuration. --- .github/workflows/ci-release.yml | 1 + .github/workflows/ci-testing.yml | 1 + .github/workflows/shared-testing-build.yml | 8 +++++++- .github/workflows/shared-testing-dotnetpack.yml | 9 ++++++++- .github/workflows/shared-testing-linux.yml | 10 ++++++++-- .github/workflows/shared-testing-macos.yml | 10 ++++++++-- .../shared-testing-windows-playwright.yml | 16 ++++++++++++---- .../shared-testing-windows-trim-aot.yml | 9 +++++++++ .github/workflows/shared-testing-windows.yml | 10 ++++++++-- .github/workflows/shared-testing.yml | 12 ++++++++++++ .../InfiniFrame.NativeBridge.csproj | 8 +++++--- .../Native/CMakeLists.txt | 12 +++++++++--- src/InfiniFrame.NativeBridge/native-build.ps1 | 12 +++++++++++- 13 files changed, 99 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index abd640296..d9acd393a 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -54,6 +54,7 @@ jobs: run_macos: true run_docs: true run_trim_aot: true + enable_test_exports: false secrets: inherit # ------------------------------------------------------------------------------------------------------------------ diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 909605230..e2aa94a49 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -56,4 +56,5 @@ jobs: run_macos: ${{ inputs.run_macos }} run_docs: ${{ inputs.run_docs }} run_trim_aot: ${{ inputs.run_trim_aot }} + enable_test_exports: true secrets: inherit diff --git a/.github/workflows/shared-testing-build.yml b/.github/workflows/shared-testing-build.yml index a5735591c..6abaf4ce9 100644 --- a/.github/workflows/shared-testing-build.yml +++ b/.github/workflows/shared-testing-build.yml @@ -15,6 +15,11 @@ on: description: 'Resolved commit SHA used by testing workflows.' type: string required: true + enable_test_exports: + description: 'Enable native test exports in testing native artifacts.' + type: boolean + required: false + default: false permissions: contents: read @@ -68,7 +73,8 @@ jobs: run: | ./src/InfiniFrame.NativeBridge/native-build.ps1 ` "Release" ` - "${{ matrix.arch }}" + "${{ matrix.arch }}" ` + "${{ inputs.enable_test_exports }}" - name: Upload Build Artifact uses: actions/upload-artifact@v7 diff --git a/.github/workflows/shared-testing-dotnetpack.yml b/.github/workflows/shared-testing-dotnetpack.yml index feaa5112c..5dd60da02 100644 --- a/.github/workflows/shared-testing-dotnetpack.yml +++ b/.github/workflows/shared-testing-dotnetpack.yml @@ -12,6 +12,11 @@ on: description: 'Commit SHA used for status/check updates' type: string required: true + enable_test_exports: + description: 'Enable native/managed test exports when validating pack.' + type: boolean + required: false + default: false permissions: contents: read @@ -66,7 +71,8 @@ jobs: --configuration Release \ --no-restore \ /p:SolutionDir=${{ github.workspace }}/ \ - /p:InfiniFrameSkipNativeBuild=true + /p:InfiniFrameSkipNativeBuild=true \ + /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Pack run: | @@ -74,6 +80,7 @@ jobs: --configuration Release \ --no-build \ /p:InfiniFrameSkipNativeBuild=true \ + /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} \ -o ./release - name: Verify NativeBridge Package Natives diff --git a/.github/workflows/shared-testing-linux.yml b/.github/workflows/shared-testing-linux.yml index 4fab3a858..5c112fb8e 100644 --- a/.github/workflows/shared-testing-linux.yml +++ b/.github/workflows/shared-testing-linux.yml @@ -15,6 +15,10 @@ on: workflow_url: type: string required: true + enable_test_exports: + type: boolean + required: false + default: false jobs: linux: @@ -86,7 +90,8 @@ jobs: --no-restore \ -p:SolutionDir=${{ github.workspace }}/ \ -p:CMakePlatform=${{ matrix.arch }} \ - -p:InfiniFrameSkipNativeBuild=true + -p:InfiniFrameSkipNativeBuild=true \ + -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Export Actions Runtime uses: actions/github-script@v9 @@ -169,7 +174,8 @@ jobs: --no-build \ --no-restore \ -p:CMakePlatform=${{ matrix.arch }} \ - -p:InfiniFrameSkipNativeBuild=true + -p:InfiniFrameSkipNativeBuild=true \ + -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Pack Tool E2E # noinspection UndefinedAction diff --git a/.github/workflows/shared-testing-macos.yml b/.github/workflows/shared-testing-macos.yml index 8c2db0dd1..6a2903d3e 100644 --- a/.github/workflows/shared-testing-macos.yml +++ b/.github/workflows/shared-testing-macos.yml @@ -15,6 +15,10 @@ on: workflow_url: type: string required: true + enable_test_exports: + type: boolean + required: false + default: false jobs: macos: @@ -88,7 +92,8 @@ jobs: --no-restore \ -p:SolutionDir=${{ github.workspace }}/ \ -p:CMakePlatform=${{ matrix.arch }} \ - -p:InfiniFrameSkipNativeBuild=true + -p:InfiniFrameSkipNativeBuild=true \ + -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Export Actions Runtime uses: actions/github-script@v9 @@ -116,7 +121,8 @@ jobs: --no-build \ --no-restore \ -p:CMakePlatform=${{ matrix.arch }} \ - -p:InfiniFrameSkipNativeBuild=true + -p:InfiniFrameSkipNativeBuild=true \ + -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Pack Tool E2E # noinspection UndefinedAction diff --git a/.github/workflows/shared-testing-windows-playwright.yml b/.github/workflows/shared-testing-windows-playwright.yml index 97b457aa0..1caf8b1ad 100644 --- a/.github/workflows/shared-testing-windows-playwright.yml +++ b/.github/workflows/shared-testing-windows-playwright.yml @@ -16,6 +16,10 @@ on: workflow_url: type: string required: true + enable_test_exports: + type: boolean + required: false + default: false permissions: contents: read @@ -146,7 +150,8 @@ jobs: --configuration Release ` --no-restore ` /p:SolutionDir=$env:GITHUB_WORKSPACE/ ` - /p:InfiniFrameSkipNativeBuild=true + /p:InfiniFrameSkipNativeBuild=true ` + /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Install Playwright Browsers shell: pwsh @@ -187,7 +192,8 @@ jobs: --no-build ` --no-restore ` --framework net8.0 ` - /p:InfiniFrameSkipNativeBuild=true + /p:InfiniFrameSkipNativeBuild=true ` + /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Run Playwright tests NET 9.0 shell: pwsh @@ -198,7 +204,8 @@ jobs: --no-build ` --no-restore ` --framework net9.0 ` - /p:InfiniFrameSkipNativeBuild=true + /p:InfiniFrameSkipNativeBuild=true ` + /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Run Playwright tests NET 10.0 shell: pwsh @@ -209,7 +216,8 @@ jobs: --no-build ` --no-restore ` --framework net10.0 ` - /p:InfiniFrameSkipNativeBuild=true + /p:InfiniFrameSkipNativeBuild=true ` + /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Update Playwright Check if: always() diff --git a/.github/workflows/shared-testing-windows-trim-aot.yml b/.github/workflows/shared-testing-windows-trim-aot.yml index d102b3ff4..b4c8db820 100644 --- a/.github/workflows/shared-testing-windows-trim-aot.yml +++ b/.github/workflows/shared-testing-windows-trim-aot.yml @@ -12,6 +12,11 @@ on: description: 'Commit SHA used for status/check updates' type: string required: true + enable_test_exports: + description: 'Enable native/managed test exports in trim/AOT validation builds.' + type: boolean + required: false + default: false permissions: contents: read @@ -75,6 +80,7 @@ jobs: -p:SolutionDir=$env:GITHUB_WORKSPACE/ ` -p:Platform=x64 ` -p:InfiniFrameSkipNativeBuild=true ` + -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} ` -p:EnableTrimAnalyzer=true ` -p:EnableAotAnalyzer=true ` -p:GeneratePackageOnBuild=false @@ -85,6 +91,7 @@ jobs: -p:SolutionDir=$env:GITHUB_WORKSPACE/ ` -p:Platform=x64 ` -p:InfiniFrameSkipNativeBuild=true ` + -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} ` -p:EnableTrimAnalyzer=true ` -p:EnableAotAnalyzer=true ` -p:GeneratePackageOnBuild=false ` @@ -96,6 +103,7 @@ jobs: -p:SolutionDir=$env:GITHUB_WORKSPACE/ ` -p:Platform=x64 ` -p:InfiniFrameSkipNativeBuild=true ` + -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} ` -p:EnableTrimAnalyzer=true ` -p:EnableAotAnalyzer=true ` -p:GeneratePackageOnBuild=false ` @@ -110,6 +118,7 @@ jobs: -p:SolutionDir=$env:GITHUB_WORKSPACE/ ` -p:Platform=x64 ` -p:InfiniFrameSkipNativeBuild=true ` + -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} ` -p:GeneratePackageOnBuild=false ` -p:SkipTypeScriptBuild=true diff --git a/.github/workflows/shared-testing-windows.yml b/.github/workflows/shared-testing-windows.yml index 36dca79f8..fc3e5aeb1 100644 --- a/.github/workflows/shared-testing-windows.yml +++ b/.github/workflows/shared-testing-windows.yml @@ -15,6 +15,10 @@ on: workflow_url: type: string required: true + enable_test_exports: + type: boolean + required: false + default: false jobs: windows: @@ -86,7 +90,8 @@ jobs: --no-restore ` /p:SolutionDir=$env:GITHUB_WORKSPACE/ ` /p:CMakePlatform=${{ matrix.arch }} ` - /p:InfiniFrameSkipNativeBuild=true + /p:InfiniFrameSkipNativeBuild=true ` + /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Prepare ARM64 Crash Diagnostics if: matrix.arch == 'arm64' @@ -200,7 +205,8 @@ jobs: --no-build ` --no-restore ` /p:CMakePlatform=${{ matrix.arch }} ` - /p:InfiniFrameSkipNativeBuild=true + /p:InfiniFrameSkipNativeBuild=true ` + /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} # - name: Upload ARM64 Crash Diagnostics # if: always() && matrix.arch == 'arm64' diff --git a/.github/workflows/shared-testing.yml b/.github/workflows/shared-testing.yml index dd0627efa..bf83bd70b 100644 --- a/.github/workflows/shared-testing.yml +++ b/.github/workflows/shared-testing.yml @@ -39,6 +39,11 @@ on: description: 'Run trim and NativeAOT compatibility validation' type: boolean required: true + enable_test_exports: + description: 'Enable native/managed test exports for test workflows' + type: boolean + required: false + default: false jobs: @@ -100,6 +105,7 @@ jobs: pr_number: ${{ inputs.pr_number }} checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} + enable_test_exports: ${{ inputs.enable_test_exports }} # noinspection UndefinedAction, UndefinedParamsPresent dotnetpack-validation: @@ -109,6 +115,7 @@ jobs: with: checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} + enable_test_exports: ${{ inputs.enable_test_exports }} # noinspection UndefinedAction, UndefinedParamsPresent linux: @@ -121,6 +128,7 @@ jobs: checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} workflow_url: ${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }} + enable_test_exports: ${{ inputs.enable_test_exports }} secrets: inherit # noinspection UndefinedAction, UndefinedParamsPresent @@ -134,6 +142,7 @@ jobs: checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} workflow_url: ${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }} + enable_test_exports: ${{ inputs.enable_test_exports }} secrets: inherit # noinspection UndefinedAction, UndefinedParamsPresent @@ -147,6 +156,7 @@ jobs: checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} workflow_url: ${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }} + enable_test_exports: ${{ inputs.enable_test_exports }} secrets: inherit # noinspection UndefinedAction, UndefinedParamsPresent @@ -160,6 +170,7 @@ jobs: checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} workflow_url: ${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }} + enable_test_exports: ${{ inputs.enable_test_exports }} secrets: inherit # noinspection UndefinedAction, UndefinedParamsPresent @@ -171,3 +182,4 @@ jobs: with: checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} + enable_test_exports: ${{ inputs.enable_test_exports }} diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index 92da674a5..0e46152d1 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -18,6 +18,8 @@ $(MSBuildThisFileDirectory)artifacts\native false + true + false $(NativeOutputRoot)\windows\x64\$(Configuration) $(NativeOutputRoot)\windows\arm64\$(Configuration) @@ -27,7 +29,7 @@ $(NativeOutputRoot)\osx\arm64\$(Configuration) - + $(DefineConstants);InfiniFrameNativeTestExports @@ -131,11 +133,11 @@ - + diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index 817a9fd3d..ca674d2d2 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -165,9 +165,15 @@ elseif (UNIX) infiniframe_setup_embed_js(${PROJECT_NAME}) endif () -target_compile_definitions(${PROJECT_NAME} PRIVATE - $<$:INFINIFRAME_BUILD_TEST_EXPORTS=1> -) +if (DEFINED INFINIFRAME_BUILD_TEST_EXPORTS) + target_compile_definitions(${PROJECT_NAME} PRIVATE + $<$:INFINIFRAME_BUILD_TEST_EXPORTS=1> + ) +else () + target_compile_definitions(${PROJECT_NAME} PRIVATE + $<$:INFINIFRAME_BUILD_TEST_EXPORTS=1> + ) +endif () # ---------------------------------------------------------------------------------------------------------------------- # Sanitizers (Debug only) diff --git a/src/InfiniFrame.NativeBridge/native-build.ps1 b/src/InfiniFrame.NativeBridge/native-build.ps1 index 91fb8f8af..7bdfc5489 100644 --- a/src/InfiniFrame.NativeBridge/native-build.ps1 +++ b/src/InfiniFrame.NativeBridge/native-build.ps1 @@ -1,6 +1,7 @@ param( [string]$Configuration = "Debug", - [string]$Arch = "x64" + [string]$Arch = "x64", + [string]$EnableTestExports = "" ) $ErrorActionPreference = "Stop" @@ -27,6 +28,12 @@ else { "osx" } New-Item -ItemType Directory -Force -Path "$ArtifactsDir/$Platform/$Arch/$Configuration" | Out-Null +if ([string]::IsNullOrWhiteSpace($EnableTestExports)) { + $EnableTestExports = if ($Configuration -ieq "Debug") { "true" } else { "false" } +} + +$EnableTestExportsCMakeValue = if ($EnableTestExports -ieq "true") { "ON" } else { "OFF" } + # ----------------------------------------------------------------------------------------------------------------- # LOCK (blocking, CI-safe, race-free) # ----------------------------------------------------------------------------------------------------------------- @@ -60,6 +67,7 @@ try { Write-Host "Configuration: $Configuration" Write-Host "Architecture : $Arch" Write-Host "Platform : $Platform" + Write-Host "Test Exports : $EnableTestExports" Write-Host "=========================================" # ----------------------------------------------------------------------------------------------------------------- @@ -89,6 +97,8 @@ try { } } + $CMakeArgs += "-DINFINIFRAME_BUILD_TEST_EXPORTS=$EnableTestExportsCMakeValue" + cmake -B $BuildDir -S $NativeDir @CMakeArgs if ($LASTEXITCODE -ne 0) { throw "CMake configure failed with exit code $LASTEXITCODE." From 75d448e65db093fe8ea3a72bb6dde3cf82d3d230 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 21:23:12 +0200 Subject: [PATCH 12/86] Add `.clang-format` and `.clang-tidy` configurations with modern C++ rules and apply formatting script --- .../Native/.clang-format | 119 ++++++++ .../Native/.clang-tidy | 266 ++++++++---------- .../native-format.ps1 | 4 + 3 files changed, 243 insertions(+), 146 deletions(-) create mode 100644 src/InfiniFrame.NativeBridge/Native/.clang-format create mode 100644 src/InfiniFrame.NativeBridge/native-format.ps1 diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-format b/src/InfiniFrame.NativeBridge/Native/.clang-format new file mode 100644 index 000000000..cdc4bfe0b --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/.clang-format @@ -0,0 +1,119 @@ +--- +BasedOnStyle: Microsoft +Language: Cpp + +# ------------------------------------------------------------------- +# General Style +# ------------------------------------------------------------------- + +IndentWidth: 4 +TabWidth: 4 +UseTab: Never + +ColumnLimit: 120 +MaxEmptyLinesToKeep: 1 + +DerivePointerAlignment: false +PointerAlignment: Left +ReferenceAlignment: Left + +NamespaceIndentation: None + +SortIncludes: false +SortUsingDeclarations: false + +# ------------------------------------------------------------------- +# Braces / K&R Style +# ------------------------------------------------------------------- + +BreakBeforeBraces: Attach + +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterStruct: false + AfterUnion: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false + +# ------------------------------------------------------------------- +# Short Statements +# ------------------------------------------------------------------- + +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AllowShortEnumsOnASingleLine: false + +# ------------------------------------------------------------------- +# Templates +# ------------------------------------------------------------------- + +AlwaysBreakTemplateDeclarations: MultiLine + +# ------------------------------------------------------------------- +# Spacing +# ------------------------------------------------------------------- + +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesInParentheses: false +SpacesInAngles: Never +SpacesInContainerLiterals: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false + +# ------------------------------------------------------------------- +# Alignment +# ------------------------------------------------------------------- + +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: DontAlign +AlignTrailingComments: false + +# ------------------------------------------------------------------- +# Access Modifiers +# ------------------------------------------------------------------- + +IndentAccessModifiers: false +AccessModifierOffset: -4 + +# ------------------------------------------------------------------- +# Includes +# ------------------------------------------------------------------- + +IncludeBlocks: Preserve + +# ------------------------------------------------------------------- +# Line Breaking +# ------------------------------------------------------------------- + +BreakConstructorInitializers: BeforeComma +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 + +# ------------------------------------------------------------------- +# C++11/20 Friendly +# ------------------------------------------------------------------- + +Standard: Latest +Cpp11BracedListStyle: true + +# ------------------------------------------------------------------- +# Misc +# ------------------------------------------------------------------- + +IndentCaseLabels: true +KeepEmptyLinesAtTheStartOfBlocks: false +ReflowComments: false +... \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-tidy b/src/InfiniFrame.NativeBridge/Native/.clang-tidy index e7949f724..fc13075d8 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-tidy +++ b/src/InfiniFrame.NativeBridge/Native/.clang-tidy @@ -1,146 +1,120 @@ -# Generated from CLion Inspection settings ---- -Checks: '-*, -bugprone-argument-comment, -bugprone-assert-side-effect, -bugprone-bad-signal-to-kill-thread, -bugprone-branch-clone, -bugprone-copy-constructor-init, -bugprone-dangling-handle, -bugprone-dynamic-static-initializers, -bugprone-fold-init-type, -bugprone-forward-declaration-namespace, -bugprone-forwarding-reference-overload, -bugprone-inaccurate-erase, -bugprone-incorrect-roundings, -bugprone-integer-division, -bugprone-lambda-function-name, -bugprone-macro-parentheses, -bugprone-macro-repeated-side-effects, -bugprone-misplaced-operator-in-strlen-in-alloc, -bugprone-misplaced-pointer-arithmetic-in-alloc, -bugprone-misplaced-widening-cast, -bugprone-move-forwarding-reference, -bugprone-multiple-statement-macro, -bugprone-no-escape, -bugprone-parent-virtual-call, -bugprone-posix-return, -bugprone-reserved-identifier, -bugprone-sizeof-container, -bugprone-sizeof-expression, -bugprone-spuriously-wake-up-functions, -bugprone-string-constructor, -bugprone-string-integer-assignment, -bugprone-string-literal-with-embedded-nul, -bugprone-suspicious-enum-usage, -bugprone-suspicious-include, -bugprone-suspicious-memset-usage, -bugprone-suspicious-missing-comma, -bugprone-suspicious-semicolon, -bugprone-suspicious-string-compare, -bugprone-suspicious-memory-comparison, -bugprone-suspicious-realloc-usage, -bugprone-swapped-arguments, -bugprone-terminating-continue, -bugprone-throw-keyword-missing, -bugprone-too-small-loop-variable, -bugprone-undefined-memory-manipulation, -bugprone-undelegated-constructor, -bugprone-unhandled-self-assignment, -bugprone-unused-raii, -bugprone-unused-return-value, -bugprone-use-after-move, -bugprone-virtual-near-miss, -cert-dcl21-cpp, -cert-dcl58-cpp, -cert-err34-c, -cert-err52-cpp, -cert-err60-cpp, -cert-flp30-c, -cert-msc50-cpp, -cert-msc51-cpp, -cert-str34-c, -cppcoreguidelines-interfaces-global-init, -cppcoreguidelines-narrowing-conversions, -cppcoreguidelines-pro-type-member-init, -cppcoreguidelines-pro-type-static-cast-downcast, -cppcoreguidelines-slicing, -google-default-arguments, -google-explicit-constructor, -google-runtime-operator, -hicpp-exception-baseclass, -hicpp-multiway-paths-covered, -misc-misplaced-const, -misc-new-delete-overloads, -misc-non-copyable-objects, -misc-throw-by-value-catch-by-reference, -misc-unconventional-assign-operator, -misc-uniqueptr-reset-release, -modernize-avoid-bind, -modernize-concat-nested-namespaces, -modernize-deprecated-headers, -modernize-deprecated-ios-base-aliases, -modernize-loop-convert, -modernize-make-shared, -modernize-make-unique, -modernize-pass-by-value, -modernize-raw-string-literal, -modernize-redundant-void-arg, -modernize-replace-auto-ptr, -modernize-replace-disallow-copy-and-assign-macro, -modernize-replace-random-shuffle, -modernize-return-braced-init-list, -modernize-shrink-to-fit, -modernize-unary-static-assert, -modernize-use-auto, -modernize-use-bool-literals, -modernize-use-emplace, -modernize-use-equals-default, -modernize-use-equals-delete, -modernize-use-nodiscard, -modernize-use-noexcept, -modernize-use-nullptr, -modernize-use-override, -modernize-use-transparent-functors, -modernize-use-uncaught-exceptions, -mpi-buffer-deref, -mpi-type-mismatch, -openmp-use-default-none, -performance-faster-string-find, -performance-for-range-copy, -performance-implicit-conversion-in-loop, -performance-inefficient-algorithm, -performance-inefficient-string-concatenation, -performance-inefficient-vector-operation, -performance-move-const-arg, -performance-move-constructor-init, -performance-no-automatic-move, -performance-noexcept-move-constructor, -performance-trivially-destructible, -performance-type-promotion-in-math-fn, -performance-unnecessary-copy-initialization, -performance-unnecessary-value-param, -portability-simd-intrinsics, -readability-avoid-const-params-in-decls, -readability-const-return-type, -readability-container-size-empty, -readability-convert-member-functions-to-static, -readability-delete-null-pointer, -readability-deleted-default, -readability-inconsistent-declaration-parameter-name, -readability-make-member-function-const, -readability-misleading-indentation, -readability-misplaced-array-index, -readability-non-const-parameter, -readability-redundant-control-flow, -readability-redundant-declaration, -readability-redundant-function-ptr-dereference, -readability-redundant-smartptr-get, -readability-redundant-string-cstr, -readability-redundant-string-init, -readability-simplify-subscript-expr, -readability-static-accessed-through-instance, -readability-static-definition-in-anonymous-namespace, -readability-string-compare, -readability-uniqueptr-delete-release, -readability-use-anyofallof' \ No newline at end of file +--- +Checks: > + -*, + + # ------------------------------------------------------------ + # Core Modern C++ + # ------------------------------------------------------------ + bugprone-*, + cppcoreguidelines-*, + modernize-*, + performance-*, + readability-*, + + # ------------------------------------------------------------ + # Removed / Disabled + # ------------------------------------------------------------ + + # Prefer classic C#-style signatures + -modernize-use-trailing-return-type, + + # Often noisy or undesirable in engine code + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-owning-memory, + + # Readability rules that conflict with PascalCase APIs + -readability-identifier-naming, + + # Too aggressive for ECS / low-level engine work + -hicpp-*, + +WarningsAsErrors: '' + +HeaderFilterRegex: '.*' + +AnalyzeTemporaryDtors: false +FormatStyle: file + +CheckOptions: + + # ------------------------------------------------------------ + # Naming Rules (C#-Style) + # ------------------------------------------------------------ + + - key: readability-identifier-naming.ClassCase + value: PascalCase + + - key: readability-identifier-naming.StructCase + value: PascalCase + + - key: readability-identifier-naming.EnumCase + value: PascalCase + + - key: readability-identifier-naming.EnumConstantCase + value: PascalCase + + - key: readability-identifier-naming.FunctionCase + value: PascalCase + + - key: readability-identifier-naming.MethodCase + value: PascalCase + + - key: readability-identifier-naming.NamespaceCase + value: PascalCase + + - key: readability-identifier-naming.VariableCase + value: camelBack + + - key: readability-identifier-naming.ParameterCase + value: camelBack + + - key: readability-identifier-naming.MemberCase + value: camelBack + + - key: readability-identifier-naming.PrivateMemberPrefix + value: _ + + - key: readability-identifier-naming.PrivateMemberCase + value: camelBack + + - key: readability-identifier-naming.ProtectedMemberPrefix + value: _ + + - key: readability-identifier-naming.ProtectedMemberCase + value: camelBack + + - key: readability-identifier-naming.ConstantCase + value: PascalCase + + - key: readability-identifier-naming.StaticConstantCase + value: PascalCase + + # ------------------------------------------------------------ + # Modernization + # ------------------------------------------------------------ + + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + + - key: modernize-loop-convert.MinConfidence + value: reasonable + + # ------------------------------------------------------------ + # Readability + # ------------------------------------------------------------ + + - key: readability-function-cognitive-complexity.Threshold + value: '25' + + - key: readability-function-size.LineThreshold + value: '300' + + # ------------------------------------------------------------ + # Performance + # ------------------------------------------------------------ + + - key: performance-move-const-arg.CheckTriviallyCopyableMove + value: 'false' +... \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/native-format.ps1 b/src/InfiniFrame.NativeBridge/native-format.ps1 new file mode 100644 index 000000000..440525bb7 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/native-format.ps1 @@ -0,0 +1,4 @@ +Get-ChildItem -Recurse -Include *.cpp,*.cxx,*.cc,*.c,*.hpp,*.hh,*.hxx,*.h,*.ixx,*.mm,*.m | +ForEach-Object { + clang-format -i $_.FullName +} \ No newline at end of file From a90504b48082ae257c7450574843f0ba373a6e4a Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 21:23:49 +0200 Subject: [PATCH 13/86] Update `.clang-format` and `.clang-tidy` configurations for consistent section header formatting. --- .../Native/.clang-format | 44 +++++++++---------- .../Native/.clang-tidy | 24 +++++----- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-format b/src/InfiniFrame.NativeBridge/Native/.clang-format index cdc4bfe0b..e532e1a90 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-format +++ b/src/InfiniFrame.NativeBridge/Native/.clang-format @@ -2,9 +2,9 @@ BasedOnStyle: Microsoft Language: Cpp -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # General Style -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- IndentWidth: 4 TabWidth: 4 @@ -22,9 +22,9 @@ NamespaceIndentation: None SortIncludes: false SortUsingDeclarations: false -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Braces / K&R Style -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- BreakBeforeBraces: Attach @@ -43,9 +43,9 @@ BraceWrapping: SplitEmptyRecord: false SplitEmptyNamespace: false -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Short Statements -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- AllowShortBlocksOnASingleLine: Empty AllowShortCaseLabelsOnASingleLine: false @@ -54,15 +54,15 @@ AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false AllowShortEnumsOnASingleLine: false -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Templates -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- AlwaysBreakTemplateDeclarations: MultiLine -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Spacing -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false @@ -72,46 +72,46 @@ SpacesInContainerLiterals: false SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: false -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Alignment -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignOperands: DontAlign AlignTrailingComments: false -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Access Modifiers -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- IndentAccessModifiers: false AccessModifierOffset: -4 -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Includes -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- IncludeBlocks: Preserve -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Line Breaking -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- BreakConstructorInitializers: BeforeComma ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # C++11/20 Friendly -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- Standard: Latest Cpp11BracedListStyle: true -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- # Misc -# ------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------- IndentCaseLabels: true KeepEmptyLinesAtTheStartOfBlocks: false diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-tidy b/src/InfiniFrame.NativeBridge/Native/.clang-tidy index fc13075d8..ba02a482e 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-tidy +++ b/src/InfiniFrame.NativeBridge/Native/.clang-tidy @@ -2,18 +2,18 @@ Checks: > -*, - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- # Core Modern C++ - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- bugprone-*, cppcoreguidelines-*, modernize-*, performance-*, readability-*, - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- # Removed / Disabled - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- # Prefer classic C#-style signatures -modernize-use-trailing-return-type, @@ -39,9 +39,9 @@ FormatStyle: file CheckOptions: - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- # Naming Rules (C#-Style) - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- - key: readability-identifier-naming.ClassCase value: PascalCase @@ -91,9 +91,9 @@ CheckOptions: - key: readability-identifier-naming.StaticConstantCase value: PascalCase - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- # Modernization - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- - key: modernize-use-nullptr.NullMacros value: 'NULL' @@ -101,9 +101,9 @@ CheckOptions: - key: modernize-loop-convert.MinConfidence value: reasonable - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- # Readability - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- - key: readability-function-cognitive-complexity.Threshold value: '25' @@ -111,9 +111,9 @@ CheckOptions: - key: readability-function-size.LineThreshold value: '300' - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- # Performance - # ------------------------------------------------------------ + # -------------------------------------------------------------------------------------------------------------------- - key: performance-move-const-arg.CheckTriviallyCopyableMove value: 'false' From 5c53d8f7238a15b886a3c582f5dbe5275a7f01d1 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 21:27:26 +0200 Subject: [PATCH 14/86] Add `NullToEmpty` utility to handle nullable strings and update export methods for safer string handling --- .../Native/Public/Exports/Exports.Dialog.cpp | 31 ++++++++++++++++--- .../Public/Exports/Exports.WindowCommands.cpp | 15 +++++---- .../Native/Public/Exports/Exports.h | 9 ++++++ 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp index 50effa5a5..46c9f3620 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp @@ -8,7 +8,14 @@ EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const A if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); - *values = window->GetDialog()->ShowOpenFile(title, defaultPath, multiSelect, filters, filterCount, resultCount); + *values = window->GetDialog()->ShowOpenFile( + NullToEmpty(title), + NullToEmpty(defaultPath), + multiSelect, + filters, + filterCount, + resultCount + ); }); } @@ -18,7 +25,12 @@ EXPORTED InteropStatus InfiniFrame_ShowOpenFolder(InfiniFrameWindow* inst, const return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); - *values = window->GetDialog()->ShowOpenFolder(title, defaultPath, multiSelect, resultCount); + *values = window->GetDialog()->ShowOpenFolder( + NullToEmpty(title), + NullToEmpty(defaultPath), + multiSelect, + resultCount + ); }); } @@ -27,7 +39,13 @@ EXPORTED InteropStatus InfiniFrame_ShowSaveFile(InfiniFrameWindow* inst, const A return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); - *value = window->GetDialog()->ShowSaveFile(title, defaultPath, filters, filterCount, defaultFileName); + *value = window->GetDialog()->ShowSaveFile( + NullToEmpty(title), + NullToEmpty(defaultPath), + filters, + filterCount, + NullToEmpty(defaultFileName) + ); }); } @@ -35,7 +53,12 @@ EXPORTED InteropStatus InfiniFrame_ShowMessage(InfiniFrameWindow* inst, const Au ResetOut(value, DialogResult::Cancel); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); - *value = window->GetDialog()->ShowMessage(title, text, buttons, icon); + *value = window->GetDialog()->ShowMessage( + NullToEmpty(title), + NullToEmpty(text), + buttons, + icon + ); }); } } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp index 244e0b6ef..7fe3f5610 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp @@ -29,8 +29,7 @@ EXPORTED InteropStatus InfiniFrame_Restore(InfiniFrameWindow* instance) { EXPORTED InteropStatus InfiniFrame_SendWebMessage(InfiniFrameWindow* instance, const AutoString message) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(message, "message")) throw std::invalid_argument("Argument 'message' is null."); - window->SendWebMessage(message); + window->SendWebMessage(NullToEmpty(message)); }); } @@ -56,8 +55,7 @@ EXPORTED InteropStatus InfiniFrame_SetFullScreen(InfiniFrameWindow* instance, co EXPORTED InteropStatus InfiniFrame_SetIconFile(InfiniFrameWindow* instance, const AutoString filename) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(filename, "filename")) throw std::invalid_argument("Argument 'filename' is null."); - window->SetIconFile(filename); + window->SetIconFile(NullToEmpty(filename)); }); } @@ -91,8 +89,7 @@ EXPORTED InteropStatus InfiniFrame_SetSize(InfiniFrameWindow* instance, const in EXPORTED InteropStatus InfiniFrame_SetTitle(InfiniFrameWindow* instance, const AutoString title) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(title, "title")) throw std::invalid_argument("Argument 'title' is null."); - window->SetTitle(title); + window->SetTitle(NullToEmpty(title)); }); } @@ -106,8 +103,10 @@ EXPORTED InteropStatus InfiniFrame_SetZoom(InfiniFrameWindow* instance, const in EXPORTED InteropStatus InfiniFrame_ShowNotification(InfiniFrameWindow* instance, const AutoString title, const AutoString body) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(title, "title") || !EnsureNotNull(body, "body")) throw std::invalid_argument("ShowNotification argument is null."); - window->ShowNotification(title, body); + window->ShowNotification( + NullToEmpty(title), + NullToEmpty(body) + ); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h index c5f531aff..e90e3c2db 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h @@ -25,4 +25,13 @@ using infiniframe::exports::RunReturnExport; using infiniframe::exports::RunWindowExportStatus; using infiniframe::exports::RunWindowReturnExport; +inline AutoString NullToEmpty(const AutoString value) noexcept { +#ifdef _WIN32 + static const wchar_t empty[] = L""; +#else + static const char empty[] = ""; +#endif + return value != nullptr ? value : const_cast(empty); +} + #endif // INFINIFRAME_PUBLIC_EXPORTS_H From 7a66912ee100f25b4f9a26e556505ad1b5118478 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 21:37:04 +0200 Subject: [PATCH 15/86] Refactor native exports to replace exceptions with early returns and update `InteropStatus` handling. Renamed `InfiniFrameNativeStatus` to `InfiniFrameNativeInteropStatus` for clarity. --- .../LibraryImports/InfiniFrameNative.cs | 206 +++++++++--------- .../InfiniFrameNativeInteropStatus.cs | 13 ++ .../LibraryImports/InfiniFrameNativeStatus.cs | 6 - .../InfiniFrameNativeTesting.cs | 4 +- .../Native/Public/Exports/Exports.Dialog.cpp | 12 +- .../Native/Public/Exports/Exports.Events.cpp | 2 +- .../Public/Exports/Exports.Lifecycle.cpp | 4 +- .../Native/Public/Exports/Exports.Memory.cpp | 6 +- .../Public/Exports/Exports.Platform.cpp | 6 +- .../Native/Public/Exports/Exports.Tests.cpp | 7 +- .../Public/Exports/Exports.WindowCommands.cpp | 4 +- .../Public/Exports/Exports.WindowState.cpp | 54 ++--- .../Native/Public/Exports/Exports.h | 5 + .../Native/Utils/ExportGuards.h | 14 +- src/InfiniFrame/Window/InfiniFrameWindow.cs | 62 +++--- 15 files changed, 213 insertions(+), 192 deletions(-) create mode 100644 src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeInteropStatus.cs delete mode 100644 src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeStatus.cs diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs index f348d97f3..f3fae3bab 100644 --- a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs +++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs @@ -18,229 +18,229 @@ public static partial class InfiniFrameNative { #region MARSHAL CALLS FROM Non-UI Thread to UI Thread [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Invoke", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus Invoke(IntPtr instance, Action callback); + internal static partial InfiniFrameNativeInteropStatus Invoke(IntPtr instance, Action callback); #endregion #region Register // ReSharper disable once UnusedMethodReturnValue.Local [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_register_win32", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus RegisterWin32(IntPtr hInstance); + internal static partial InfiniFrameNativeInteropStatus RegisterWin32(IntPtr hInstance); // ReSharper disable once UnusedMethodReturnValue.Local [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_register_mac", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus RegisterMac(); + internal static partial InfiniFrameNativeInteropStatus RegisterMac(); #endregion #region CTOR-DTOR [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ctor", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus Constructor([MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))] in InfiniFrameNativeParameters parameters, out IntPtr value); + internal static partial InfiniFrameNativeInteropStatus Constructor([MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))] in InfiniFrameNativeParameters parameters, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_dtor"), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus Destructor(IntPtr instance); + internal static partial InfiniFrameNativeInteropStatus Destructor(IntPtr instance); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_AddCustomSchemeName", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus AddCustomSchemeName(IntPtr instance, string scheme); + internal static partial InfiniFrameNativeInteropStatus AddCustomSchemeName(IntPtr instance, string scheme); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Close", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus Close(IntPtr instance); + internal static partial InfiniFrameNativeInteropStatus Close(IntPtr instance); #endregion #region Get [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_getHwnd_win32", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetWindowHandlerWin32(IntPtr instance, out IntPtr value); + internal static partial InfiniFrameNativeInteropStatus GetWindowHandlerWin32(IntPtr instance, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetAllMonitors", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetAllMonitors(IntPtr instance, CppGetAllMonitorsDelegate callback); + internal static partial InfiniFrameNativeInteropStatus GetAllMonitors(IntPtr instance, CppGetAllMonitorsDelegate callback); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTransparentEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetContextMenuEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetDevToolsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFullScreen", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool fullScreen); + internal static partial InfiniFrameNativeInteropStatus GetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool fullScreen); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetGrantBrowserPermissions", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetGrantBrowserPermissions(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool grant); + internal static partial InfiniFrameNativeInteropStatus GetGrantBrowserPermissions(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool grant); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetUserAgent", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetUserAgent(IntPtr instance, out IntPtr value); + internal static partial InfiniFrameNativeInteropStatus GetUserAgent(IntPtr instance, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMediaAutoplayEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetMediaAutoplayEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetMediaAutoplayEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFileSystemAccessEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetFileSystemAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetFileSystemAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetWebSecurityEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetWebSecurityEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetWebSecurityEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetJavascriptClipboardAccessEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetJavascriptClipboardAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetJavascriptClipboardAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMediaStreamEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetMediaStreamEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetMediaStreamEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetSmoothScrollingEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetSmoothScrollingEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetSmoothScrollingEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetIgnoreCertificateErrorsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetIgnoreCertificateErrorsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetIgnoreCertificateErrorsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetNotificationsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetNotificationsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); + internal static partial InfiniFrameNativeInteropStatus GetNotificationsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetPosition", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetPosition(IntPtr instance, out int x, out int y); + internal static partial InfiniFrameNativeInteropStatus GetPosition(IntPtr instance, out int x, out int y); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetResizable", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool resizable); + internal static partial InfiniFrameNativeInteropStatus GetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool resizable); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetScreenDpi", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetScreenDpi(IntPtr instance, out uint value); + internal static partial InfiniFrameNativeInteropStatus GetScreenDpi(IntPtr instance, out uint value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetSize(IntPtr instance, out int width, out int height); + internal static partial InfiniFrameNativeInteropStatus GetSize(IntPtr instance, out int width, out int height); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMaxSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetMaxSize(IntPtr instance, out int maxWidth, out int maxHeight); + internal static partial InfiniFrameNativeInteropStatus GetMaxSize(IntPtr instance, out int maxWidth, out int maxHeight); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMinSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetMinSize(IntPtr instance, out int minWidth, out int minHeight); + internal static partial InfiniFrameNativeInteropStatus GetMinSize(IntPtr instance, out int minWidth, out int minHeight); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTitle", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetTitle(IntPtr instance, out IntPtr value); + internal static partial InfiniFrameNativeInteropStatus GetTitle(IntPtr instance, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTopmost", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool topmost); + internal static partial InfiniFrameNativeInteropStatus GetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool topmost); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetZoom", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetZoom(IntPtr instance, out int zoom); + internal static partial InfiniFrameNativeInteropStatus GetZoom(IntPtr instance, out int zoom); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMaximized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool maximized); + internal static partial InfiniFrameNativeInteropStatus GetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool maximized); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMinimized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool minimized); + internal static partial InfiniFrameNativeInteropStatus GetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool minimized); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetZoomEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool zoomEnabled); + internal static partial InfiniFrameNativeInteropStatus GetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool zoomEnabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetIconFileName", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetIconFileName(IntPtr instance, out IntPtr value); + internal static partial InfiniFrameNativeInteropStatus GetIconFileName(IntPtr instance, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFocused", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus GetFocused(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool isFocused); + internal static partial InfiniFrameNativeInteropStatus GetFocused(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool isFocused); #endregion #region Navigate [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_NavigateToString", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus NavigateToString(IntPtr instance, string content); + internal static partial InfiniFrameNativeInteropStatus NavigateToString(IntPtr instance, string content); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_NavigateToUrl", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus NavigateToUrl(IntPtr instance, string url); + internal static partial InfiniFrameNativeInteropStatus NavigateToUrl(IntPtr instance, string url); #endregion #region Set [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_setWebView2RuntimePath_win32", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetWebView2RuntimePath_win32(IntPtr instance, string webView2RuntimePath); + internal static partial InfiniFrameNativeInteropStatus SetWebView2RuntimePath_win32(IntPtr instance, string webView2RuntimePath); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTransparentEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); + internal static partial InfiniFrameNativeInteropStatus SetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetContextMenuEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); + internal static partial InfiniFrameNativeInteropStatus SetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetDevToolsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); + internal static partial InfiniFrameNativeInteropStatus SetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetFullScreen", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool fullScreen); + internal static partial InfiniFrameNativeInteropStatus SetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool fullScreen); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMaximized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool maximized); + internal static partial InfiniFrameNativeInteropStatus SetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool maximized); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMaxSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetMaxSize(IntPtr instance, int maxWidth, int maxHeight); + internal static partial InfiniFrameNativeInteropStatus SetMaxSize(IntPtr instance, int maxWidth, int maxHeight); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMinimized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool minimized); + internal static partial InfiniFrameNativeInteropStatus SetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool minimized); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMinSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetMinSize(IntPtr instance, int minWidth, int minHeight); + internal static partial InfiniFrameNativeInteropStatus SetMinSize(IntPtr instance, int minWidth, int minHeight); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetResizable", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool resizable); + internal static partial InfiniFrameNativeInteropStatus SetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool resizable); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetPosition", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetPosition(IntPtr instance, int x, int y); + internal static partial InfiniFrameNativeInteropStatus SetPosition(IntPtr instance, int x, int y); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetSize(IntPtr instance, int width, int height); + internal static partial InfiniFrameNativeInteropStatus SetSize(IntPtr instance, int width, int height); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTitle", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetTitle(IntPtr instance, string? title); + internal static partial InfiniFrameNativeInteropStatus SetTitle(IntPtr instance, string? title); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTopmost", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool topmost); + internal static partial InfiniFrameNativeInteropStatus SetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool topmost); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetIconFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetIconFile(IntPtr instance, string filename); + internal static partial InfiniFrameNativeInteropStatus SetIconFile(IntPtr instance, string filename); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetZoom", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetZoom(IntPtr instance, int zoom); + internal static partial InfiniFrameNativeInteropStatus SetZoom(IntPtr instance, int zoom); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetZoomEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool zoomEnabled); + internal static partial InfiniFrameNativeInteropStatus SetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool zoomEnabled); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetFocused", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SetFocused(IntPtr instance); + internal static partial InfiniFrameNativeInteropStatus SetFocused(IntPtr instance); #endregion #region Misc [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Center", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus Center(IntPtr instance); + internal static partial InfiniFrameNativeInteropStatus Center(IntPtr instance); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Restore", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus Restore(IntPtr instance); + internal static partial InfiniFrameNativeInteropStatus Restore(IntPtr instance); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ClearBrowserAutoFill", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus ClearBrowserAutoFill(IntPtr instance); + internal static partial InfiniFrameNativeInteropStatus ClearBrowserAutoFill(IntPtr instance); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SendWebMessage", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus SendWebMessage(IntPtr instance, string message); + internal static partial InfiniFrameNativeInteropStatus SendWebMessage(IntPtr instance, string message); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowNotification", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus ShowNotification(IntPtr instance, string title, string body); + internal static partial InfiniFrameNativeInteropStatus ShowNotification(IntPtr instance, string title, string body); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_WaitForExit", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus WaitForExit(IntPtr instance); + internal static partial InfiniFrameNativeInteropStatus WaitForExit(IntPtr instance); #endregion #region Dialog [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowOpenFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus ShowOpenFile(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, string[] filters, int filtersCount, out int resultCount, out IntPtr values); + internal static partial InfiniFrameNativeInteropStatus ShowOpenFile(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, string[] filters, int filtersCount, out int resultCount, out IntPtr values); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowOpenFolder", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus ShowOpenFolder(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, out int resultCount, out IntPtr values); + internal static partial InfiniFrameNativeInteropStatus ShowOpenFolder(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, out int resultCount, out IntPtr values); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowSaveFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus ShowSaveFile(IntPtr inst, string title, string defaultPath, string[] filters, int filtersCount, string? defaultFileName, out IntPtr value); + internal static partial InfiniFrameNativeInteropStatus ShowSaveFile(IntPtr inst, string title, string defaultPath, string[] filters, int filtersCount, string? defaultFileName, out IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowMessage", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus ShowMessage(IntPtr inst, string title, string text, InfiniFrameDialogButtons buttons, InfiniFrameDialogIcon icon, out InfiniFrameDialogResult value); + internal static partial InfiniFrameNativeInteropStatus ShowMessage(IntPtr inst, string title, string text, InfiniFrameDialogButtons buttons, InfiniFrameDialogIcon icon, out InfiniFrameDialogResult value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_FreeString", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus FreeString(IntPtr value); + internal static partial InfiniFrameNativeInteropStatus FreeString(IntPtr value); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_FreeStringArray", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - internal static partial InfiniFrameNativeStatus FreeStringArray(IntPtr values, int count); + internal static partial InfiniFrameNativeInteropStatus FreeStringArray(IntPtr values, int count); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetLastErrorMessage", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - private static partial InfiniFrameNativeStatus GetLastErrorMessagePtr(out IntPtr value); + private static partial InfiniFrameNativeInteropStatus GetLastErrorMessagePtr(out IntPtr value); #endregion #region Overloads @@ -252,57 +252,57 @@ public static partial class InfiniFrameNative { : Marshal.PtrToStringUTF8(ptr); } - internal static InfiniFrameNativeStatus GetHeight(IntPtr instance, out int height) + internal static InfiniFrameNativeInteropStatus GetHeight(IntPtr instance, out int height) => GetSize(instance, out _, out height); - internal static InfiniFrameNativeStatus GetWidth(IntPtr instance, out int width) + internal static InfiniFrameNativeInteropStatus GetWidth(IntPtr instance, out int width) => GetSize(instance, out width, out _); - internal static InfiniFrameNativeStatus GetMaxHeight(IntPtr instance, out int maxHeight) + internal static InfiniFrameNativeInteropStatus GetMaxHeight(IntPtr instance, out int maxHeight) => GetMaxSize(instance, out _, out maxHeight); - internal static InfiniFrameNativeStatus GetMaxWidth(IntPtr instance, out int maxWidth) + internal static InfiniFrameNativeInteropStatus GetMaxWidth(IntPtr instance, out int maxWidth) => GetMaxSize(instance, out maxWidth, out _); - internal static InfiniFrameNativeStatus GetMinHeight(IntPtr instance, out int minHeight) + internal static InfiniFrameNativeInteropStatus GetMinHeight(IntPtr instance, out int minHeight) => GetMinSize(instance, out _, out minHeight); - internal static InfiniFrameNativeStatus GetMinWidth(IntPtr instance, out int minWidth) + internal static InfiniFrameNativeInteropStatus GetMinWidth(IntPtr instance, out int minWidth) => GetMinSize(instance, out minWidth, out _); - internal static InfiniFrameNativeStatus GetLeft(IntPtr instance, out int left) + internal static InfiniFrameNativeInteropStatus GetLeft(IntPtr instance, out int left) => GetPosition(instance, out left, out _); - internal static InfiniFrameNativeStatus GetTop(IntPtr instance, out int top) + internal static InfiniFrameNativeInteropStatus GetTop(IntPtr instance, out int top) => GetPosition(instance, out _, out top); - internal static InfiniFrameNativeStatus GetSize(IntPtr instance, out Size size) { - InfiniFrameNativeStatus status = GetSize(instance, out int width, out int height); + internal static InfiniFrameNativeInteropStatus GetSize(IntPtr instance, out Size size) { + InfiniFrameNativeInteropStatus status = GetSize(instance, out int width, out int height); size = new Size(width, height); return status; } - internal static InfiniFrameNativeStatus GetMaxSize(IntPtr instance, out Size size) { - InfiniFrameNativeStatus status = GetMaxSize(instance, out int width, out int height); + internal static InfiniFrameNativeInteropStatus GetMaxSize(IntPtr instance, out Size size) { + InfiniFrameNativeInteropStatus status = GetMaxSize(instance, out int width, out int height); size = new Size(width, height); return status; } - internal static InfiniFrameNativeStatus GetMinSize(IntPtr instance, out Size size) { - InfiniFrameNativeStatus status = GetMinSize(instance, out int width, out int height); + internal static InfiniFrameNativeInteropStatus GetMinSize(IntPtr instance, out Size size) { + InfiniFrameNativeInteropStatus status = GetMinSize(instance, out int width, out int height); size = new Size(width, height); return status; } - internal static InfiniFrameNativeStatus GetPosition(IntPtr instance, out Point position) { - InfiniFrameNativeStatus status = GetPosition(instance, out int left, out int top); + internal static InfiniFrameNativeInteropStatus GetPosition(IntPtr instance, out Point position) { + InfiniFrameNativeInteropStatus status = GetPosition(instance, out int left, out int top); position = new Point(left, top); return status; } - internal static InfiniFrameNativeStatus GetWindowRectangle(IntPtr instance, out int x, out int y, out int width, out int height) { - InfiniFrameNativeStatus sizeStatus = GetSize(instance, out width, out height); - if (sizeStatus != InfiniFrameNativeStatus.Success) { + internal static InfiniFrameNativeInteropStatus GetWindowRectangle(IntPtr instance, out int x, out int y, out int width, out int height) { + InfiniFrameNativeInteropStatus sizeStatus = GetSize(instance, out width, out height); + if (sizeStatus != InfiniFrameNativeInteropStatus.Success) { x = 0; y = 0; return sizeStatus; @@ -311,14 +311,14 @@ internal static InfiniFrameNativeStatus GetWindowRectangle(IntPtr instance, out return GetPosition(instance, out x, out y); } - internal static InfiniFrameNativeStatus GetWindowRectangle(IntPtr instance, out Rectangle rectangle) { - InfiniFrameNativeStatus status = GetWindowRectangle(instance, out int x, out int y, out int width, out int height); + internal static InfiniFrameNativeInteropStatus GetWindowRectangle(IntPtr instance, out Rectangle rectangle) { + InfiniFrameNativeInteropStatus status = GetWindowRectangle(instance, out int x, out int y, out int width, out int height); rectangle = new Rectangle(x, y, width, height); return status; } - internal static InfiniFrameNativeStatus GetUserAgent(IntPtr instance, out string? userAgent) { - InfiniFrameNativeStatus status = GetUserAgent(instance, out IntPtr ptr); + internal static InfiniFrameNativeInteropStatus GetUserAgent(IntPtr instance, out string? userAgent) { + InfiniFrameNativeInteropStatus status = GetUserAgent(instance, out IntPtr ptr); try { userAgent = PtrToNativeString(ptr); } @@ -331,8 +331,8 @@ internal static InfiniFrameNativeStatus GetUserAgent(IntPtr instance, out string return status; } - internal static InfiniFrameNativeStatus GetTitle(IntPtr instance, out string? title) { - InfiniFrameNativeStatus status = GetTitle(instance, out IntPtr ptr); + internal static InfiniFrameNativeInteropStatus GetTitle(IntPtr instance, out string? title) { + InfiniFrameNativeInteropStatus status = GetTitle(instance, out IntPtr ptr); try { title = PtrToNativeString(ptr); } @@ -345,8 +345,8 @@ internal static InfiniFrameNativeStatus GetTitle(IntPtr instance, out string? ti return status; } - internal static InfiniFrameNativeStatus GetIconFileName(IntPtr instance, out string iconFileName) { - InfiniFrameNativeStatus status = GetIconFileName(instance, out IntPtr ptr); + internal static InfiniFrameNativeInteropStatus GetIconFileName(IntPtr instance, out string iconFileName) { + InfiniFrameNativeInteropStatus status = GetIconFileName(instance, out IntPtr ptr); try { iconFileName = PtrToNativeString(ptr) ?? string.Empty; } @@ -360,8 +360,8 @@ internal static InfiniFrameNativeStatus GetIconFileName(IntPtr instance, out str } internal static string? GetLastErrorMessage() { - InfiniFrameNativeStatus status = GetLastErrorMessagePtr(out IntPtr ptr); - if (status != InfiniFrameNativeStatus.Success || ptr == IntPtr.Zero) return null; + InfiniFrameNativeInteropStatus status = GetLastErrorMessagePtr(out IntPtr ptr); + if (status != InfiniFrameNativeInteropStatus.Success || ptr == IntPtr.Zero) return null; try { return PtrToNativeString(ptr); @@ -371,16 +371,16 @@ internal static InfiniFrameNativeStatus GetIconFileName(IntPtr instance, out str } } - internal static InfiniFrameNativeStatus EnsureSucceeded(InfiniFrameNativeStatus status, string operationName) { + internal static InfiniFrameNativeInteropStatus EnsureSucceeded(InfiniFrameNativeInteropStatus status, string operationName) { int fallbackLastError = Marshal.GetLastPInvokeError(); - if (status is InfiniFrameNativeStatus.Success && fallbackLastError is 0) return status; + if (status is InfiniFrameNativeInteropStatus.Success && fallbackLastError is 0) return status; - InfiniFrameNativeStatus fallbackStatus = GetLastErrorMessagePtr(out IntPtr ptr); + InfiniFrameNativeInteropStatus fallbackStatus = GetLastErrorMessagePtr(out IntPtr ptr); string? fallbackMessage; - if (fallbackStatus != InfiniFrameNativeStatus.Success || ptr == IntPtr.Zero) { + if (fallbackStatus != InfiniFrameNativeInteropStatus.Success || ptr == IntPtr.Zero) { fallbackMessage = "No native error message provided."; } else { diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeInteropStatus.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeInteropStatus.cs new file mode 100644 index 000000000..d86e6c874 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeInteropStatus.cs @@ -0,0 +1,13 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +namespace InfiniFrame.NativeBridge; +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +internal enum InfiniFrameNativeInteropStatus { + Success = 0, + InvalidArgument = 22, + OutParameterSetToInvalidNull = 2001, + OperationFailed = 14 +} diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeStatus.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeStatus.cs deleted file mode 100644 index 6ff79abec..000000000 --- a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeStatus.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace InfiniFrame.NativeBridge; -internal enum InfiniFrameNativeStatus { - Success = 0, - InvalidArgument = 22, - OperationFailed = 14 -} diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs index b0bece63c..96606950f 100644 --- a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs +++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs @@ -14,14 +14,14 @@ namespace InfiniFrame.NativeBridge; public static partial class InfiniFrameNativeTesting { #if InfiniFrameNativeTestExports [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrameNativeTests_NativeParametersReturnAsIs", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - private static partial InfiniFrameNativeStatus NativeParametersReturnAsIsNative( + private static partial InfiniFrameNativeInteropStatus NativeParametersReturnAsIsNative( [MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))] in InfiniFrameNativeParameters parameters, out IntPtr newParameters ); [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrameNativeTests_FreeInitParams", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - private static partial InfiniFrameNativeStatus FreeInitParamsNative(IntPtr parameters); + private static partial InfiniFrameNativeInteropStatus FreeInitParamsNative(IntPtr parameters); /// /// Returns a native pointer to a newly allocated InfiniFrameInitParams clone. diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp index 46c9f3620..3aff97b41 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp @@ -5,8 +5,8 @@ EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const A ResetOut(resultCount, 0); ResetOut(values, static_cast(nullptr)); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); - if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + if (!EnsureOutNotNull(resultCount, "resultCount")) return; + if (!EnsureOutNotNull(values, "values")) return; if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); *values = window->GetDialog()->ShowOpenFile( NullToEmpty(title), @@ -23,8 +23,8 @@ EXPORTED InteropStatus InfiniFrame_ShowOpenFolder(InfiniFrameWindow* inst, const ResetOut(resultCount, 0); ResetOut(values, static_cast(nullptr)); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(resultCount, "resultCount")) throw std::invalid_argument("Argument 'resultCount' is null."); - if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + if (!EnsureOutNotNull(resultCount, "resultCount")) return; + if (!EnsureOutNotNull(values, "values")) return; *values = window->GetDialog()->ShowOpenFolder( NullToEmpty(title), NullToEmpty(defaultPath), @@ -37,7 +37,7 @@ EXPORTED InteropStatus InfiniFrame_ShowOpenFolder(InfiniFrameWindow* inst, const EXPORTED InteropStatus InfiniFrame_ShowSaveFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, AutoString* filters, const int filterCount, const AutoString defaultFileName, AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); *value = window->GetDialog()->ShowSaveFile( NullToEmpty(title), @@ -52,7 +52,7 @@ EXPORTED InteropStatus InfiniFrame_ShowSaveFile(InfiniFrameWindow* inst, const A EXPORTED InteropStatus InfiniFrame_ShowMessage(InfiniFrameWindow* inst, const AutoString title, const AutoString text, const DialogButtons buttons, const DialogIcon icon, DialogResult* value) { ResetOut(value, DialogResult::Cancel); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; *value = window->GetDialog()->ShowMessage( NullToEmpty(title), NullToEmpty(text), diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp index 706bd670e..e3940594f 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp @@ -3,7 +3,7 @@ extern "C" { EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(scheme, "scheme")) throw std::invalid_argument("Argument 'scheme' is null."); + if (!EnsureNotNull(scheme, "scheme")) return; window->AddCustomSchemeName(scheme); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp index 915367249..2437932ba 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp @@ -4,7 +4,7 @@ extern "C" { EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { ResetOut(value, static_cast(nullptr)); return RunExportStatus([&] { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; if (initParams == nullptr) throw std::invalid_argument("Argument 'initParams' is null."); if (initParams->Size != static_cast(sizeof(InfiniFrameInitParams))) { throw std::invalid_argument("InfiniFrameInitParams.Size does not match native struct size."); @@ -16,7 +16,7 @@ EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, Infin EXPORTED InteropStatus InfiniFrame_dtor(InfiniFrameWindow* instance) { return RunExportStatus([&] { - if (!EnsureNotNull(instance, "instance")) throw std::invalid_argument("Argument 'instance' is null."); + if (!EnsureNotNull(instance, "instance")) return; std::unique_ptr guard{instance}; }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp index 7b207555f..8fad4dac0 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp @@ -3,7 +3,7 @@ extern "C" { EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { return RunExportStatus([&] { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureNotNull(value, "value")) return; #ifdef _WIN32 delete[] value; #elif __linux__ @@ -16,7 +16,7 @@ EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { EXPORTED InteropStatus InfiniFrame_FreeStringArray(AutoString* values, const int count) { return RunExportStatus([&] { - if (!EnsureNotNull(values, "values")) throw std::invalid_argument("Argument 'values' is null."); + if (!EnsureNotNull(values, "values")) return; if (count < 0) throw std::invalid_argument("Argument 'count' must be >= 0."); for (int i = 0; i < count; ++i) { if (values[i] != nullptr) { @@ -36,7 +36,7 @@ EXPORTED InteropStatus InfiniFrame_FreeStringArray(AutoString* values, const int EXPORTED InteropStatus InfiniFrame_GetLastErrorMessage(AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunExportStatus([&] { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; *value = GetLastErrorMessageCopy(); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp index 89caed16c..e15f54bf1 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp @@ -12,14 +12,14 @@ EXPORTED InteropStatus InfiniFrame_register_win32(const HINSTANCE hInstance) { EXPORTED InteropStatus InfiniFrame_getHwnd_win32(InfiniFrameWindow* instance, HWND* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; *value = window->getHwnd(); }); } EXPORTED InteropStatus InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindow*, const AutoString webView2RuntimePath) { return RunExportStatus([&] { - if (!EnsureNotNull(webView2RuntimePath, "webView2RuntimePath")) throw std::invalid_argument("Argument 'webView2RuntimePath' is null."); + if (!EnsureNotNull(webView2RuntimePath, "webView2RuntimePath")) return; InfiniFrameWindow::SetWebView2RuntimePath(webView2RuntimePath); }); } @@ -27,7 +27,7 @@ EXPORTED InteropStatus InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindo EXPORTED InteropStatus InfiniFrame_GetNotificationsEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetNotificationsEnabled(enabled); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp index 51b5010da..6b364aa09 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp @@ -46,8 +46,9 @@ extern "C" { } return RunExportStatus([&] { - if (!EnsureNotNull(params, "params") || !EnsureNotNull(new_params, "new_params")) { - throw std::invalid_argument("Test export argument is null."); + if (!EnsureNotNull(params, "params") + || !EnsureNotNull(new_params, "new_params", ::InteropStatus::OutParameterSetToInvalidNull)) { + return; } *new_params = new InfiniFrameInitParams(); @@ -113,7 +114,7 @@ extern "C" { EXPORTED InteropStatus InfiniFrameNativeTests_FreeInitParams(InfiniFrameInitParams* params) { return RunExportStatus([&] { if (!EnsureNotNull(params, "params")) { - throw std::invalid_argument("Argument 'params' is null."); + return; } delete[] params->StartString; diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp index 7fe3f5610..30a49b1a8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp @@ -11,14 +11,14 @@ EXPORTED InteropStatus InfiniFrame_ClearBrowserAutoFill(InfiniFrameWindow* insta EXPORTED InteropStatus InfiniFrame_NavigateToString(InfiniFrameWindow* instance, const AutoString content) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(content, "content")) throw std::invalid_argument("Argument 'content' is null."); + if (!EnsureNotNull(content, "content")) return; window->NavigateToString(content); }); } EXPORTED InteropStatus InfiniFrame_NavigateToUrl(InfiniFrameWindow* instance, const AutoString url) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(url, "url")) throw std::invalid_argument("Argument 'url' is null."); + if (!EnsureNotNull(url, "url")) return; window->NavigateToUrl(url); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp index 2b8812099..5ef584256 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp @@ -4,7 +4,7 @@ extern "C" { EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetTransparentEnabled(enabled); }); } @@ -12,7 +12,7 @@ EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* inst EXPORTED InteropStatus InfiniFrame_GetContextMenuEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetContextMenuEnabled(enabled); }); } @@ -20,7 +20,7 @@ EXPORTED InteropStatus InfiniFrame_GetContextMenuEnabled(InfiniFrameWindow* inst EXPORTED InteropStatus InfiniFrame_GetZoomEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetZoomEnabled(enabled); }); } @@ -28,7 +28,7 @@ EXPORTED InteropStatus InfiniFrame_GetZoomEnabled(InfiniFrameWindow* instance, b EXPORTED InteropStatus InfiniFrame_GetDevToolsEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetDevToolsEnabled(enabled); }); } @@ -36,7 +36,7 @@ EXPORTED InteropStatus InfiniFrame_GetDevToolsEnabled(InfiniFrameWindow* instanc EXPORTED InteropStatus InfiniFrame_GetFullScreen(InfiniFrameWindow* instance, bool* fullScreen) { ResetOut(fullScreen, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(fullScreen, "fullScreen")) throw std::invalid_argument("Argument 'fullScreen' is null."); + if (!EnsureOutNotNull(fullScreen, "fullScreen")) return; window->GetFullScreen(fullScreen); }); } @@ -44,7 +44,7 @@ EXPORTED InteropStatus InfiniFrame_GetFullScreen(InfiniFrameWindow* instance, bo EXPORTED InteropStatus InfiniFrame_GetGrantBrowserPermissions(InfiniFrameWindow* instance, bool* grant) { ResetOut(grant, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(grant, "grant")) throw std::invalid_argument("Argument 'grant' is null."); + if (!EnsureOutNotNull(grant, "grant")) return; window->GetGrantBrowserPermissions(grant); }); } @@ -52,7 +52,7 @@ EXPORTED InteropStatus InfiniFrame_GetGrantBrowserPermissions(InfiniFrameWindow* EXPORTED InteropStatus InfiniFrame_GetUserAgent(InfiniFrameWindow* instance, AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; *value = window->GetUserAgent(); }); } @@ -60,7 +60,7 @@ EXPORTED InteropStatus InfiniFrame_GetUserAgent(InfiniFrameWindow* instance, Aut EXPORTED InteropStatus InfiniFrame_GetMediaAutoplayEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetMediaAutoplayEnabled(enabled); }); } @@ -68,7 +68,7 @@ EXPORTED InteropStatus InfiniFrame_GetMediaAutoplayEnabled(InfiniFrameWindow* in EXPORTED InteropStatus InfiniFrame_GetFileSystemAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetFileSystemAccessEnabled(enabled); }); } @@ -76,7 +76,7 @@ EXPORTED InteropStatus InfiniFrame_GetFileSystemAccessEnabled(InfiniFrameWindow* EXPORTED InteropStatus InfiniFrame_GetWebSecurityEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetWebSecurityEnabled(enabled); }); } @@ -84,7 +84,7 @@ EXPORTED InteropStatus InfiniFrame_GetWebSecurityEnabled(InfiniFrameWindow* inst EXPORTED InteropStatus InfiniFrame_GetJavascriptClipboardAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetJavascriptClipboardAccessEnabled(enabled); }); } @@ -92,7 +92,7 @@ EXPORTED InteropStatus InfiniFrame_GetJavascriptClipboardAccessEnabled(InfiniFra EXPORTED InteropStatus InfiniFrame_GetMediaStreamEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetMediaStreamEnabled(enabled); }); } @@ -100,7 +100,7 @@ EXPORTED InteropStatus InfiniFrame_GetMediaStreamEnabled(InfiniFrameWindow* inst EXPORTED InteropStatus InfiniFrame_GetSmoothScrollingEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetSmoothScrollingEnabled(enabled); }); } @@ -108,7 +108,7 @@ EXPORTED InteropStatus InfiniFrame_GetSmoothScrollingEnabled(InfiniFrameWindow* EXPORTED InteropStatus InfiniFrame_GetMaximized(InfiniFrameWindow* instance, bool* isMaximized) { ResetOut(isMaximized, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(isMaximized, "isMaximized")) throw std::invalid_argument("Argument 'isMaximized' is null."); + if (!EnsureOutNotNull(isMaximized, "isMaximized")) return; window->GetMaximized(isMaximized); }); } @@ -116,7 +116,7 @@ EXPORTED InteropStatus InfiniFrame_GetMaximized(InfiniFrameWindow* instance, boo EXPORTED InteropStatus InfiniFrame_GetMinimized(InfiniFrameWindow* instance, bool* isMinimized) { ResetOut(isMinimized, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(isMinimized, "isMinimized")) throw std::invalid_argument("Argument 'isMinimized' is null."); + if (!EnsureOutNotNull(isMinimized, "isMinimized")) return; window->GetMinimized(isMinimized); }); } @@ -124,7 +124,7 @@ EXPORTED InteropStatus InfiniFrame_GetMinimized(InfiniFrameWindow* instance, boo EXPORTED InteropStatus InfiniFrame_GetIgnoreCertificateErrorsEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(enabled, "enabled")) throw std::invalid_argument("Argument 'enabled' is null."); + if (!EnsureOutNotNull(enabled, "enabled")) return; window->GetIgnoreCertificateErrorsEnabled(enabled); }); } @@ -132,7 +132,7 @@ EXPORTED InteropStatus InfiniFrame_GetIgnoreCertificateErrorsEnabled(InfiniFrame EXPORTED InteropStatus InfiniFrame_GetPosition(InfiniFrameWindow* instance, int* x, int* y) { ResetOut2(x, y, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(x, "x") || !EnsureNotNull(y, "y")) throw std::invalid_argument("GetPosition out argument is null."); + if (!EnsureOutNotNull(x, "x") || !EnsureOutNotNull(y, "y")) return; window->GetPosition(x, y); }); } @@ -140,7 +140,7 @@ EXPORTED InteropStatus InfiniFrame_GetPosition(InfiniFrameWindow* instance, int* EXPORTED InteropStatus InfiniFrame_GetResizable(InfiniFrameWindow* instance, bool* resizable) { ResetOut(resizable, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(resizable, "resizable")) throw std::invalid_argument("Argument 'resizable' is null."); + if (!EnsureOutNotNull(resizable, "resizable")) return; window->GetResizable(resizable); }); } @@ -148,7 +148,7 @@ EXPORTED InteropStatus InfiniFrame_GetResizable(InfiniFrameWindow* instance, boo EXPORTED InteropStatus InfiniFrame_GetScreenDpi(InfiniFrameWindow* instance, unsigned int* value) { ResetOut(value, static_cast(0)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; *value = window->GetScreenDpi(); }); } @@ -156,7 +156,7 @@ EXPORTED InteropStatus InfiniFrame_GetScreenDpi(InfiniFrameWindow* instance, uns EXPORTED InteropStatus InfiniFrame_GetSize(InfiniFrameWindow* instance, int* width, int* height) { ResetOut2(width, height, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetSize out argument is null."); + if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) return; window->GetSize(width, height); }); } @@ -164,7 +164,7 @@ EXPORTED InteropStatus InfiniFrame_GetSize(InfiniFrameWindow* instance, int* wid EXPORTED InteropStatus InfiniFrame_GetMaxSize(InfiniFrameWindow* instance, int* width, int* height) { ResetOut2(width, height, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetMaxSize out argument is null."); + if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) return; window->GetMaxSize(width, height); }); } @@ -172,7 +172,7 @@ EXPORTED InteropStatus InfiniFrame_GetMaxSize(InfiniFrameWindow* instance, int* EXPORTED InteropStatus InfiniFrame_GetMinSize(InfiniFrameWindow* instance, int* width, int* height) { ResetOut2(width, height, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(width, "width") || !EnsureNotNull(height, "height")) throw std::invalid_argument("GetMinSize out argument is null."); + if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) return; window->GetMinSize(width, height); }); } @@ -180,7 +180,7 @@ EXPORTED InteropStatus InfiniFrame_GetMinSize(InfiniFrameWindow* instance, int* EXPORTED InteropStatus InfiniFrame_GetTitle(InfiniFrameWindow* instance, AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; *value = window->GetTitle(); }); } @@ -188,7 +188,7 @@ EXPORTED InteropStatus InfiniFrame_GetTitle(InfiniFrameWindow* instance, AutoStr EXPORTED InteropStatus InfiniFrame_GetTopmost(InfiniFrameWindow* instance, bool* topmost) { ResetOut(topmost, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(topmost, "topmost")) throw std::invalid_argument("Argument 'topmost' is null."); + if (!EnsureOutNotNull(topmost, "topmost")) return; window->GetTopmost(topmost); }); } @@ -196,7 +196,7 @@ EXPORTED InteropStatus InfiniFrame_GetTopmost(InfiniFrameWindow* instance, bool* EXPORTED InteropStatus InfiniFrame_GetZoom(InfiniFrameWindow* instance, int* zoom) { ResetOut(zoom, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(zoom, "zoom")) throw std::invalid_argument("Argument 'zoom' is null."); + if (!EnsureOutNotNull(zoom, "zoom")) return; window->GetZoom(zoom); }); } @@ -204,7 +204,7 @@ EXPORTED InteropStatus InfiniFrame_GetZoom(InfiniFrameWindow* instance, int* zoo EXPORTED InteropStatus InfiniFrame_GetFocused(InfiniFrameWindow* instance, bool* isFocused) { ResetOut(isFocused, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(isFocused, "isFocused")) throw std::invalid_argument("Argument 'isFocused' is null."); + if (!EnsureOutNotNull(isFocused, "isFocused")) return; window->GetFocused(isFocused); }); } @@ -212,7 +212,7 @@ EXPORTED InteropStatus InfiniFrame_GetFocused(InfiniFrameWindow* instance, bool* EXPORTED InteropStatus InfiniFrame_GetIconFileName(InfiniFrameWindow* instance, AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(value, "value")) throw std::invalid_argument("Argument 'value' is null."); + if (!EnsureOutNotNull(value, "value")) return; *value = window->GetIconFileName(); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h index e90e3c2db..ac5592110 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h @@ -25,6 +25,11 @@ using infiniframe::exports::RunReturnExport; using infiniframe::exports::RunWindowExportStatus; using infiniframe::exports::RunWindowReturnExport; +template +inline bool EnsureOutNotNull(T* value, const char* argumentName) noexcept { + return infiniframe::exports::EnsureNotNull(value, argumentName, InteropStatus::OutParameterSetToInvalidNull); +} + inline AutoString NullToEmpty(const AutoString value) noexcept { #ifdef _WIN32 static const wchar_t empty[] = L""; diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h index 2fba3ae74..894aa7748 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h @@ -18,12 +18,14 @@ enum class InteropStatus : int { Success = 0, InvalidArgument = 22, + OutParameterSetToInvalidNull = 2001, OperationFailed = 14 }; namespace infiniframe::exports { namespace detail { inline thread_local std::string g_lastErrorMessage; + inline thread_local InteropStatus g_lastStatus = InteropStatus::Success; inline void SetLastErrorCode(const InteropStatus status) noexcept { #ifdef _WIN32 @@ -43,11 +45,13 @@ namespace infiniframe::exports { inline void SetFailure(const InteropStatus status, std::string message) noexcept { g_lastErrorMessage = std::move(message); + g_lastStatus = status; SetLastErrorCode(status); } inline void SetSuccess() noexcept { g_lastErrorMessage.clear(); + g_lastStatus = InteropStatus::Success; ClearLastErrorCode(); } @@ -125,19 +129,23 @@ namespace infiniframe::exports { } template - inline bool EnsureNotNull(T* value, const char* argumentName) noexcept { + inline bool EnsureNotNull(T* value, const char* argumentName, const InteropStatus status = InteropStatus::InvalidArgument) noexcept { if (value != nullptr) { return true; } - detail::SetFailure(InteropStatus::InvalidArgument, std::string("Argument '") + argumentName + "' is null."); + detail::SetFailure(status, std::string("Argument '") + argumentName + "' is null."); return false; } template inline InteropStatus RunExportStatus(Fn&& fn) noexcept { try { + detail::SetSuccess(); std::forward(fn)(); + if (detail::g_lastStatus != InteropStatus::Success) { + return detail::g_lastStatus; + } detail::SetSuccess(); return InteropStatus::Success; } @@ -154,7 +162,7 @@ namespace infiniframe::exports { inline InteropStatus RunWindowExportStatus(InfiniFrameWindow* instance, Fn&& fn) noexcept { return RunExportStatus([&] { if (!EnsureNotNull(instance, "instance")) { - throw std::invalid_argument("Argument 'instance' is null."); + return; } std::forward(fn)(instance); diff --git a/src/InfiniFrame/Window/InfiniFrameWindow.cs b/src/InfiniFrame/Window/InfiniFrameWindow.cs index 0adbb86da..9d8714662 100644 --- a/src/InfiniFrame/Window/InfiniFrameWindow.cs +++ b/src/InfiniFrame/Window/InfiniFrameWindow.cs @@ -53,7 +53,7 @@ public void Invoke(Action workItem) { static void RunWithNativeStatusCheck(Action action) { Marshal.SetLastPInvokeError(0); action(); - InfiniFrameNative.EnsureSucceeded(InfiniFrameNativeStatus.Success, "Invoke"); + InfiniFrameNative.EnsureSucceeded(InfiniFrameNativeInteropStatus.Success, "Invoke"); } // If we're already on the UI thread, no need to dispatch @@ -422,7 +422,7 @@ public void Initialize() { string[] nativeFilters = GetNativeFilters(filters, foldersOnly); Invoke(() => { - InfiniFrameNativeStatus status = foldersOnly + InfiniFrameNativeInteropStatus status = foldersOnly ? InfiniFrameNative.ShowOpenFolder(InstanceHandle, title, defaultPath, multiSelect, out int resultCount, out IntPtr ptrResults) : InfiniFrameNative.ShowOpenFile(InstanceHandle, title, defaultPath, multiSelect, nativeFilters, nativeFilters.Length, out resultCount, out ptrResults); InfiniFrameNative.EnsureSucceeded(status, foldersOnly ? nameof(InfiniFrameNative.ShowOpenFolder) : nameof(InfiniFrameNative.ShowOpenFile)); @@ -478,7 +478,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// Thrown when accessed from a non-Windows platform. [DebuggerBrowsable(DebuggerBrowsableState.Never)] public IntPtr WindowHandle => OperatingSystem.IsWindows() - ? InvokeUtility.InvokeAndReturn( + ? InvokeUtility.InvokeAndReturn( this, InfiniFrameNative.GetWindowHandlerWin32, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetWindowHandlerWin32))) @@ -516,7 +516,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// An ApplicationException is thrown if the window hasn't been initialized yet. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public uint ScreenDpi => InvokeUtility.InvokeAndReturn( + public uint ScreenDpi => InvokeUtility.InvokeAndReturn( this, InfiniFrameNative.GetScreenDpi, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetScreenDpi))); @@ -551,51 +551,51 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool Transparent => OperatingSystem.IsWindows() ? Configuration.StartupParameters.Transparent// on windows it can only be set at startup - : InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTransparentEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetTransparentEnabled))); + : InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTransparentEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetTransparentEnabled))); /// /// When true, the user can access the browser control's context menu. /// By default, this is set to true. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool ContextMenuEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetContextMenuEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetContextMenuEnabled))); + public bool ContextMenuEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetContextMenuEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetContextMenuEnabled))); /// /// When true, the user can access the browser control's developer tools. /// By default, this is set to true. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool DevToolsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetDevToolsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetDevToolsEnabled))); + public bool DevToolsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetDevToolsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetDevToolsEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool MediaAutoplayEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMediaAutoplayEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMediaAutoplayEnabled))); + public bool MediaAutoplayEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMediaAutoplayEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMediaAutoplayEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public string? UserAgent => InvokeUtility.InvokeAndReturn( + public string? UserAgent => InvokeUtility.InvokeAndReturn( this, InfiniFrameNative.GetUserAgent, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetUserAgent))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool FileSystemAccessEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFileSystemAccessEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFileSystemAccessEnabled))); + public bool FileSystemAccessEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFileSystemAccessEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFileSystemAccessEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool WebSecurityEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetWebSecurityEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetWebSecurityEnabled))); + public bool WebSecurityEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetWebSecurityEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetWebSecurityEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool JavascriptClipboardAccessEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetJavascriptClipboardAccessEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetJavascriptClipboardAccessEnabled))); + public bool JavascriptClipboardAccessEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetJavascriptClipboardAccessEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetJavascriptClipboardAccessEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool MediaStreamEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMediaStreamEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMediaStreamEnabled))); + public bool MediaStreamEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMediaStreamEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMediaStreamEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool SmoothScrollingEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetSmoothScrollingEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetSmoothScrollingEnabled))); + public bool SmoothScrollingEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetSmoothScrollingEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetSmoothScrollingEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool IgnoreCertificateErrorsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetIgnoreCertificateErrorsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetIgnoreCertificateErrorsEnabled))); + public bool IgnoreCertificateErrorsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetIgnoreCertificateErrorsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetIgnoreCertificateErrorsEnabled))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool NotificationsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetNotificationsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetNotificationsEnabled))); + public bool NotificationsEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetNotificationsEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetNotificationsEnabled))); /// /// This property returns or sets the fullscreen status of the window. @@ -603,14 +603,14 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// By default, this is set to false. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool FullScreen => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFullScreen, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFullScreen))); + public bool FullScreen => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFullScreen, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFullScreen))); /// /// Gets whether the native browser control grants all requests for access to local resources /// such as the user's camera and microphone. By default, this is set to true. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool GrantBrowserPermissions => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetGrantBrowserPermissions, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetGrantBrowserPermissions))); + public bool GrantBrowserPermissions => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetGrantBrowserPermissions, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetGrantBrowserPermissions))); /// /// Gets the Height property of the native window in pixels. @@ -626,7 +626,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// Gets the icon file for the native window title bar. /// The file must be located on the local machine and cannot be a URL. The default is none. /// - public string IconFilePath => InvokeUtility.InvokeAndReturn( + public string IconFilePath => InvokeUtility.InvokeAndReturn( this, InfiniFrameNative.GetIconFileName, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetIconFileName))); @@ -639,7 +639,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi public Point Location => InvokeUtility.InvokeAndReturn( this, (IntPtr handle, out Point value) => { - InfiniFrameNativeStatus status = InfiniFrameNative.GetPosition(handle, out int left, out int top); + InfiniFrameNativeInteropStatus status = InfiniFrameNative.GetPosition(handle, out int left, out int top); value = new Point(left, top); return status; }, @@ -661,13 +661,13 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// Default is false. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool Maximized => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMaximized, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMaximized))); + public bool Maximized => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMaximized, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMaximized))); /// /// Gets whether the native window is currently within focus /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool Focused => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFocused, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFocused))); + public bool Focused => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetFocused, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetFocused))); /// /// Gets the maximum size of the native window in pixels. @@ -676,7 +676,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi public Size MaxSize => InvokeUtility.InvokeAndReturn( this, (IntPtr handle, out Size value) => { - InfiniFrameNativeStatus status = InfiniFrameNative.GetMaxSize(handle, out int width, out int height); + InfiniFrameNativeInteropStatus status = InfiniFrameNative.GetMaxSize(handle, out int width, out int height); value = new Size(width, height); return status; }, @@ -704,7 +704,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// Gets whether the native window is minimized (hidden). /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool Minimized => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMinimized, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMinimized))); + public bool Minimized => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetMinimized, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetMinimized))); /// /// Gets the minimum size of the native window in pixels. @@ -713,7 +713,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi public Size MinSize => InvokeUtility.InvokeAndReturn( this, (IntPtr handle, out Size value) => { - InfiniFrameNativeStatus status = InfiniFrameNative.GetMinSize(handle, out int width, out int height); + InfiniFrameNativeInteropStatus status = InfiniFrameNative.GetMinSize(handle, out int width, out int height); value = new Size(width, height); return status; }, @@ -742,7 +742,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// Default is true. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool Resizable => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetResizable, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetResizable))); + public bool Resizable => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetResizable, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetResizable))); /// /// Gets the native window Size. This represents the width and the height of the window in pixels. @@ -752,7 +752,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi public Size Size => InvokeUtility.InvokeAndReturn( this, (IntPtr handle, out Size value) => { - InfiniFrameNativeStatus status = InfiniFrameNative.GetSize(handle, out int width, out int height); + InfiniFrameNativeInteropStatus status = InfiniFrameNative.GetSize(handle, out int width, out int height); value = new Size(width, height); return status; }, @@ -832,7 +832,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// The default is "InfiniFrame". /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public string? Title => InvokeUtility.InvokeAndReturn( + public string? Title => InvokeUtility.InvokeAndReturn( this, InfiniFrameNative.GetTitle, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetTitle))); @@ -852,7 +852,7 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// Default is false. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool TopMost => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTopmost, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetTopmost))); + public bool TopMost => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetTopmost, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetTopmost))); /// /// Gets the native window width in pixels. @@ -870,9 +870,9 @@ private static string[] GetNativeFilters((string Name, string[] Extensions)[] fi /// /// 100 = 100%, 50 = 50% [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public int Zoom => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetZoom, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetZoom))); + public int Zoom => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetZoom, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetZoom))); [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public bool ZoomEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetZoomEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetZoomEnabled))); + public bool ZoomEnabled => InvokeUtility.InvokeAndReturn(this, InfiniFrameNative.GetZoomEnabled, s => InfiniFrameNative.EnsureSucceeded(s, nameof(InfiniFrameNative.GetZoomEnabled))); #endregion } From 3b1820f6632e5e33ccb0c19471c9549fd520b05c Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 21:38:48 +0200 Subject: [PATCH 16/86] Simplify `.clang-format` and `.clang-tidy` configurations by removing unnecessary line breaks. --- src/InfiniFrame.NativeBridge/Native/.clang-format | 6 ++---- src/InfiniFrame.NativeBridge/Native/.clang-tidy | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-format b/src/InfiniFrame.NativeBridge/Native/.clang-format index e532e1a90..e0911ae7b 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-format +++ b/src/InfiniFrame.NativeBridge/Native/.clang-format @@ -1,5 +1,4 @@ ---- -BasedOnStyle: Microsoft +BasedOnStyle: Microsoft Language: Cpp # ---------------------------------------------------------------------------------------------------------------------- @@ -115,5 +114,4 @@ Cpp11BracedListStyle: true IndentCaseLabels: true KeepEmptyLinesAtTheStartOfBlocks: false -ReflowComments: false -... \ No newline at end of file +ReflowComments: false \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-tidy b/src/InfiniFrame.NativeBridge/Native/.clang-tidy index ba02a482e..1bf493b30 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-tidy +++ b/src/InfiniFrame.NativeBridge/Native/.clang-tidy @@ -1,5 +1,4 @@ ---- -Checks: > +Checks: > -*, # -------------------------------------------------------------------------------------------------------------------- @@ -116,5 +115,4 @@ CheckOptions: # -------------------------------------------------------------------------------------------------------------------- - key: performance-move-const-arg.CheckTriviallyCopyableMove - value: 'false' -... \ No newline at end of file + value: 'false' \ No newline at end of file From 47f7e056ef5c0a5dc38a445984f34b8dd7d3868e Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 21:45:47 +0200 Subject: [PATCH 17/86] Add `native-tidy.ps1` script and update `native-format.ps1` to exclude dependencies and packages directories. --- src/InfiniFrame.NativeBridge/native-format.ps1 | 7 ++++++- src/InfiniFrame.NativeBridge/native-tidy.ps1 | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/InfiniFrame.NativeBridge/native-tidy.ps1 diff --git a/src/InfiniFrame.NativeBridge/native-format.ps1 b/src/InfiniFrame.NativeBridge/native-format.ps1 index 440525bb7..1d9209d86 100644 --- a/src/InfiniFrame.NativeBridge/native-format.ps1 +++ b/src/InfiniFrame.NativeBridge/native-format.ps1 @@ -1,4 +1,9 @@ -Get-ChildItem -Recurse -Include *.cpp,*.cxx,*.cc,*.c,*.hpp,*.hh,*.hxx,*.h,*.ixx,*.mm,*.m | +Get-ChildItem -Recurse -File -Include *.cpp,*.cxx,*.cc,*.c,*.hpp,*.hh,*.hxx,*.h,*.ixx,*.mm,*.m | +Where-Object { + $_.FullName -notmatch '\\Dependencies\\' -and + $_.FullName -notmatch '\\packages\\' +} | ForEach-Object { + Write-Host "Formatting $($_.FullName)" clang-format -i $_.FullName } \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/native-tidy.ps1 b/src/InfiniFrame.NativeBridge/native-tidy.ps1 new file mode 100644 index 000000000..5d56eca75 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/native-tidy.ps1 @@ -0,0 +1,8 @@ +Get-ChildItem . -Recurse -File -Include *.cpp,*.cc,*.cxx,*.c,*.hpp,*.h | +Where-Object { + $_.FullName -notmatch '\\(build|out|bin|obj|vcpkg)\\' +} | +ForEach-Object { + Write-Host "Running clang-tidy on $($_.FullName)" + clang-tidy $_.FullName -p build --fix +} \ No newline at end of file From 0447744dc79cf2e566ced9fd840847ec5e5e3d88 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:07:34 +0200 Subject: [PATCH 18/86] Refactor `native-tidy.ps1` to improve maintainability, add parameterization for build directory and error fixing, and enhance Visual Studio environment setup with robust error handling. --- src/InfiniFrame.NativeBridge/native-tidy.ps1 | 136 +++++++++++++++++-- 1 file changed, 128 insertions(+), 8 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/native-tidy.ps1 b/src/InfiniFrame.NativeBridge/native-tidy.ps1 index 5d56eca75..6eae1c4b1 100644 --- a/src/InfiniFrame.NativeBridge/native-tidy.ps1 +++ b/src/InfiniFrame.NativeBridge/native-tidy.ps1 @@ -1,8 +1,128 @@ -Get-ChildItem . -Recurse -File -Include *.cpp,*.cc,*.cxx,*.c,*.hpp,*.h | -Where-Object { - $_.FullName -notmatch '\\(build|out|bin|obj|vcpkg)\\' -} | -ForEach-Object { - Write-Host "Running clang-tidy on $($_.FullName)" - clang-tidy $_.FullName -p build --fix -} \ No newline at end of file +param( + [string]$BuildDirectoryName = "build-clang-tidy", + [switch]$FixErrors +) + +$ErrorActionPreference = "Stop" + +function Invoke-ExternalCommand { + param( + [Parameter(Mandatory = $true)][string]$FilePath, + [string[]]$Arguments = @() + ) + + & $FilePath @Arguments + if ($LASTEXITCODE -ne 0) { + throw "Command failed with exit code ${LASTEXITCODE}: $FilePath $($Arguments -join ' ')" + } +} + +function Get-VsInstallationPath { + $vsWhere = Join-Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vsWhere)) { + return $null + } + + $path = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($path)) { + return $null + } + + return $path.Trim() +} + +function Import-VsDevEnvironment { + param([Parameter(Mandatory = $true)][string]$VsDevCmdPath) + + $envDump = & cmd.exe /s /c "`"$VsDevCmdPath`" -arch=x64 -host_arch=x64 >nul && set" + if ($LASTEXITCODE -ne 0) { + throw "Failed to initialize Visual Studio developer environment using '$VsDevCmdPath'." + } + + foreach ($line in $envDump) { + $separatorIndex = $line.IndexOf("=") + if ($separatorIndex -lt 1) { + continue + } + + $name = $line.Substring(0, $separatorIndex) + $value = $line.Substring($separatorIndex + 1) + Set-Item -Path "env:$name" -Value $value + } +} + +$NativeRoot = Join-Path $PSScriptRoot "Native" +$BuildDirectory = Join-Path $NativeRoot $BuildDirectoryName + +Push-Location $NativeRoot + +try { + $clangTidy = Get-Command clang-tidy -ErrorAction SilentlyContinue + if (-not $clangTidy) { + throw "clang-tidy was not found on PATH." + } + + $vsInstallPath = Get-VsInstallationPath + if (-not $vsInstallPath) { + throw "Could not locate a Visual Studio installation with C++ tools." + } + + $vsDevCmd = Join-Path $vsInstallPath "Common7\Tools\VsDevCmd.bat" + if (-not (Test-Path $vsDevCmd)) { + throw "VsDevCmd.bat not found at '$vsDevCmd'." + } + + Write-Host "Initializing Visual Studio developer environment..." + Import-VsDevEnvironment -VsDevCmdPath $vsDevCmd + + $ninja = Get-Command ninja -ErrorAction SilentlyContinue + if (-not $ninja) { + throw "ninja was not found on PATH after VsDevCmd initialization." + } + + Write-Host "Generating compile_commands.json in '$BuildDirectoryName'..." + Invoke-ExternalCommand -FilePath "cmake" -Arguments @( + "-S", ".", + "-B", $BuildDirectory, + "--fresh", + "-G", "Ninja", + "-DCMAKE_MAKE_PROGRAM=$($ninja.Source)", + "-DCMAKE_BUILD_TYPE=Debug", + "-DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON", + "-DCMAKE_CXX_SCAN_FOR_MODULES=OFF", + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + ) + + $compileCommandsPath = Join-Path $BuildDirectory "compile_commands.json" + if (-not (Test-Path $compileCommandsPath)) { + throw "compile_commands.json was not generated at '$compileCommandsPath'." + } + + Write-Host "Running clang-tidy..." + + $sourceFiles = Get-ChildItem . -Recurse -File -Include *.cpp,*.cc,*.cxx,*.c,*.mm | + Where-Object { + $_.FullName -notmatch '\\(build($|[-_][^\\]+)?|out|bin|obj|vcpkg|Dependencies|packages)\\' + } + + foreach ($sourceFile in $sourceFiles) { + Write-Host "Running clang-tidy on $($sourceFile.FullName)" + + $tidyArgs = @( + $sourceFile.FullName, + "-p", $BuildDirectory, + "--fix" + ) + + if ($FixErrors) { + $tidyArgs += "--fix-errors" + } + + Invoke-ExternalCommand -FilePath $clangTidy.Source -Arguments $tidyArgs + } + + Write-Host "clang-tidy complete." +} +finally { + Pop-Location +} From 7df7ee5505f049d03d8ba82ed7eb13fe6767a7cd Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:10:21 +0200 Subject: [PATCH 19/86] Update `native-format.ps1` to exclude `build` directory and refine `.clang-format` settings with improved parameter alignment. Remove redundant option from `.clang-tidy`. --- src/InfiniFrame.NativeBridge/Native/.clang-format | 4 +++- src/InfiniFrame.NativeBridge/Native/.clang-tidy | 1 - src/InfiniFrame.NativeBridge/native-format.ps1 | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-format b/src/InfiniFrame.NativeBridge/Native/.clang-format index e0911ae7b..99d6ce4eb 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-format +++ b/src/InfiniFrame.NativeBridge/Native/.clang-format @@ -97,6 +97,8 @@ IncludeBlocks: Preserve # Line Breaking # ---------------------------------------------------------------------------------------------------------------------- +AlignAfterOpenBracket: BlockIndent +BinPackParameters: false BreakConstructorInitializers: BeforeComma ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 @@ -114,4 +116,4 @@ Cpp11BracedListStyle: true IndentCaseLabels: true KeepEmptyLinesAtTheStartOfBlocks: false -ReflowComments: false \ No newline at end of file +ReflowComments: false diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-tidy b/src/InfiniFrame.NativeBridge/Native/.clang-tidy index 1bf493b30..2e0d41699 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-tidy +++ b/src/InfiniFrame.NativeBridge/Native/.clang-tidy @@ -33,7 +33,6 @@ WarningsAsErrors: '' HeaderFilterRegex: '.*' -AnalyzeTemporaryDtors: false FormatStyle: file CheckOptions: diff --git a/src/InfiniFrame.NativeBridge/native-format.ps1 b/src/InfiniFrame.NativeBridge/native-format.ps1 index 1d9209d86..cb3a64da8 100644 --- a/src/InfiniFrame.NativeBridge/native-format.ps1 +++ b/src/InfiniFrame.NativeBridge/native-format.ps1 @@ -1,7 +1,8 @@ Get-ChildItem -Recurse -File -Include *.cpp,*.cxx,*.cc,*.c,*.hpp,*.hh,*.hxx,*.h,*.ixx,*.mm,*.m | Where-Object { $_.FullName -notmatch '\\Dependencies\\' -and - $_.FullName -notmatch '\\packages\\' + $_.FullName -notmatch '\\packages\\' -and + $_.FullName -notmatch '\\build\\' } | ForEach-Object { Write-Host "Formatting $($_.FullName)" From 5605a0475559e0079851a8f22effcdc24fc31b18 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:10:36 +0200 Subject: [PATCH 20/86] Refactor native exports for consistent code style by adding braces to single-line conditional statements and aligning parameter formatting across methods. --- .../InfiniFrame.NativeBridge.csproj | 1 - .../Native/Dependencies/simdutf/simdutf.h | 11161 +++++++--------- .../Native/Embedded/Embedded.h | 52 +- .../Platform/Linux/Core/UiDispatcher.Gtk.cpp | 40 +- .../Platform/Linux/Core/WindowCore.Gtk.cpp | 10 +- .../Linux/Core/WindowInitialization.Gtk.cpp | 59 +- .../Linux/Core/WindowLifecycle.Gtk.cpp | 14 +- .../Platform/Linux/Core/WindowSignals.Gtk.cpp | 106 +- .../Platform/Linux/Core/WindowState.Gtk.cpp | 17 +- .../Native/Platform/Linux/Dialog.cpp | 45 +- .../Linux/WebKit/WebKit.Gtk.Internal.h | 10 +- .../Linux/WebKit/WebKitCustomSchemes.Gtk.cpp | 45 +- .../Platform/Linux/WebKit/WebKitHost.Gtk.cpp | 48 +- .../Linux/WebKit/WebKitMessaging.Gtk.cpp | 62 +- .../Linux/WebKit/WebKitSettings.Gtk.cpp | 33 +- .../Windows/Core/UiDispatcher.Win32.cpp | 11 +- .../Windows/Core/WindowEncoding.Win32.cpp | 18 +- .../Windows/Core/WindowEvents.Win32.cpp | 6 +- .../Windows/Core/WindowLifecycle.Win32.cpp | 95 +- .../Windows/Core/WindowProc.Win32.cpp | 33 +- .../Windows/Core/WindowState.Win32.cpp | 25 +- .../Windows/Core/WindowStorage.Win32.cpp | 23 +- .../Windows/Core/WindowTracing.Win32.cpp | 12 +- .../Native/Platform/Windows/DarkMode.cpp | 213 +- .../Native/Platform/Windows/DarkMode.h | 68 +- .../Native/Platform/Windows/Dialog.cpp | 139 +- .../Native/Platform/Windows/ToastHandler.h | 47 +- .../Windows/WebView/WebView2Attach.Win32.cpp | 312 +- .../WebView/WebView2Controller.Win32.cpp | 22 +- .../Windows/WebView/WebView2Host.Win32.cpp | 19 +- .../Windows/WebView/WebView2Runtime.Win32.cpp | 13 +- .../Platform/Windows/Window.Win32.Context.h | 30 +- .../Native/Public/Exports/Exports.Dialog.cpp | 91 +- .../Native/Public/Exports/Exports.Events.cpp | 9 +- .../Public/Exports/Exports.Lifecycle.cpp | 9 +- .../Native/Public/Exports/Exports.Memory.cpp | 12 +- .../Public/Exports/Exports.Platform.cpp | 15 +- .../Native/Public/Exports/Exports.Tests.cpp | 177 +- .../Public/Exports/Exports.WindowCommands.cpp | 18 +- .../Public/Exports/Exports.WindowState.cpp | 81 +- .../Native/Public/Exports/Exports.h | 3 +- .../Native/Public/InfiniFrameDialog.h | 68 +- .../Native/Public/InfiniFrameWindow.h | 426 +- .../Native/Types/Callbacks.h | 2 +- .../Native/Types/Monitor.h | 3 +- .../Native/Utils/ErrorCode.h | 8 +- .../Native/Utils/Event.h | 173 +- .../Native/Utils/ExportGuards.h | 272 +- .../Native/Utils/Result.h | 3 +- 49 files changed, 6448 insertions(+), 7711 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index 0e46152d1..0a18ce86f 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -54,7 +54,6 @@ - diff --git a/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h index b1af31254..7cb7476d2 100644 --- a/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h +++ b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h @@ -2,6 +2,7 @@ /* begin file include/simdutf.h */ #ifndef SIMDUTF_H #define SIMDUTF_H +#include #include /* begin file include/simdutf/compiler_check.h */ @@ -75,11 +76,10 @@ #include #endif -#if defined(__apple_build_version__) - #if __apple_build_version__ < 14000000 - #define SIMDUTF_SPAN_DISABLED \ - 1 // apple-clang/13 doesn't support std::convertible_to - #endif +#ifdef __apple_build_version__ +#if __apple_build_version__ < 14000000 +#define SIMDUTF_SPAN_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to +#endif #endif #if SIMDUTF_CPLUSPLUS20 @@ -103,8 +103,8 @@ #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) #define SIMDUTF_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#elif defined(_WIN32) - #define SIMDUTF_IS_BIG_ENDIAN 0 +#elifdef _WIN32 +#define SIMDUTF_IS_BIG_ENDIAN 0 #else #if defined(__APPLE__) || \ defined(__FreeBSD__) // defined __BYTE_ORDER__ && defined @@ -282,12 +282,11 @@ _Pragma(SIMDUTF_STRINGIFY(clang attribute push( \ __attribute__((target(T))), apply_to = function))) #define SIMDUTF_UNTARGET_REGION _Pragma("clang attribute pop") - #elif defined(__GNUC__) - // GCC is easier - #define SIMDUTF_TARGET_REGION(T) \ - _Pragma("GCC push_options") _Pragma(SIMDUTF_STRINGIFY(GCC target(T))) - #define SIMDUTF_UNTARGET_REGION _Pragma("GCC pop_options") - #endif // clang then gcc +#elifdef __GNUC__ +// GCC is easier +#define SIMDUTF_TARGET_REGION(T) _Pragma("GCC push_options") _Pragma(SIMDUTF_STRINGIFY(GCC target(T))) +#define SIMDUTF_UNTARGET_REGION _Pragma("GCC pop_options") +#endif // clang then gcc #endif // defined(SIMDUTF_IS_X86_64) || defined(SIMDUTF_IS_LSX) @@ -449,46 +448,44 @@ #define simdutf_log_assert(cond, msg) #endif -#if defined(SIMDUTF_REGULAR_VISUAL_STUDIO) - #define SIMDUTF_DEPRECATED __declspec(deprecated) +#ifdef SIMDUTF_REGULAR_VISUAL_STUDIO +#define SIMDUTF_DEPRECATED __declspec(deprecated) - #define simdutf_really_inline __forceinline // really inline in release mode - #define simdutf_always_inline __forceinline // always inline, no matter what - #define simdutf_never_inline __declspec(noinline) +#define simdutf_really_inline __forceinline // really inline in release mode +#define simdutf_always_inline __forceinline // always inline, no matter what +#define simdutf_never_inline __declspec(noinline) - #define simdutf_unused - #define simdutf_warn_unused +#define simdutf_unused +#define simdutf_warn_unused - #ifndef simdutf_likely - #define simdutf_likely(x) x - #endif - #ifndef simdutf_unlikely - #define simdutf_unlikely(x) x - #endif +#ifndef simdutf_likely +#define simdutf_likely(x) x +#endif +#ifndef simdutf_unlikely +#define simdutf_unlikely(x) x +#endif - #define SIMDUTF_PUSH_DISABLE_WARNINGS __pragma(warning(push)) - #define SIMDUTF_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0)) - #define SIMDUTF_DISABLE_VS_WARNING(WARNING_NUMBER) \ - __pragma(warning(disable : WARNING_NUMBER)) - // Get rid of Intellisense-only warnings (Code Analysis) - // Though __has_include is C++17, it is supported in Visual Studio 2017 or - // better (_MSC_VER>=1910). - #ifdef __has_include - #if __has_include() - #include - #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS \ - SIMDUTF_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS) - #endif - #endif +#define SIMDUTF_PUSH_DISABLE_WARNINGS __pragma(warning(push)) +#define SIMDUTF_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0)) +#define SIMDUTF_DISABLE_VS_WARNING(WARNING_NUMBER) __pragma(warning(disable : WARNING_NUMBER)) +// Get rid of Intellisense-only warnings (Code Analysis) +// Though __has_include is C++17, it is supported in Visual Studio 2017 or +// better (_MSC_VER>=1910). +#ifdef __has_include +#if __has_include() +#include +#define SIMDUTF_DISABLE_UNDESIRED_WARNINGS SIMDUTF_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS) +#endif +#endif - #ifndef SIMDUTF_DISABLE_UNDESIRED_WARNINGS - #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS - #endif +#ifndef SIMDUTF_DISABLE_UNDESIRED_WARNINGS +#define SIMDUTF_DISABLE_UNDESIRED_WARNINGS +#endif - #define SIMDUTF_DISABLE_DEPRECATED_WARNING SIMDUTF_DISABLE_VS_WARNING(4996) - #define SIMDUTF_DISABLE_STRICT_OVERFLOW_WARNING - #define SIMDUTF_POP_DISABLE_WARNINGS __pragma(warning(pop)) - #define SIMDUTF_DISABLE_UNUSED_WARNING +#define SIMDUTF_DISABLE_DEPRECATED_WARNING SIMDUTF_DISABLE_VS_WARNING(4996) +#define SIMDUTF_DISABLE_STRICT_OVERFLOW_WARNING +#define SIMDUTF_POP_DISABLE_WARNINGS __pragma(warning(pop)) +#define SIMDUTF_DISABLE_UNUSED_WARNING #else // SIMDUTF_REGULAR_VISUAL_STUDIO #if defined(__OPTIMIZE__) || defined(NDEBUG) #define simdutf_really_inline inline __attribute__((always_inline)) @@ -529,7 +526,7 @@ #define SIMDUTF_PRAGMA(P) _Pragma(#P) #define SIMDUTF_DISABLE_GCC_WARNING(WARNING) \ SIMDUTF_PRAGMA(GCC diagnostic ignored #WARNING) - #if defined(SIMDUTF_CLANG_VISUAL_STUDIO) + #ifdef SIMDUTF_CLANG_VISUAL_STUDIO #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS \ SIMDUTF_DISABLE_GCC_WARNING(-Wmicrosoft-include) #else @@ -642,12 +639,11 @@ enum endianness { #endif }; -simdutf_warn_unused simdutf_really_inline constexpr bool -match_system(endianness e) { - return e == endianness::NATIVE; +simdutf_warn_unused simdutf_really_inline constexpr auto match_system(endianness e) -> bool { + return e == endianness::NATIVE; } -simdutf_warn_unused std::string_view to_string(encoding_type bom); +simdutf_warn_unused auto to_string(encoding_type bom) -> std::string_view; // Note that BOM for UTF8 is discouraged. namespace BOM { @@ -659,15 +655,15 @@ namespace BOM { * @return the corresponding encoding */ -simdutf_warn_unused encoding_type check_bom(const uint8_t *byte, size_t length); -simdutf_warn_unused encoding_type check_bom(const char *byte, size_t length); +simdutf_warn_unused auto check_bom(const uint8_t* byte, size_t length) -> encoding_type; +simdutf_warn_unused auto check_bom(const char* byte, size_t length) -> encoding_type; /** * Returns the size, in bytes, of the BOM for a given encoding type. * Note that UTF8 BOM are discouraged. * @param bom the encoding type * @return the size in bytes of the corresponding BOM */ -simdutf_warn_unused size_t bom_byte_size(encoding_type bom); +simdutf_warn_unused auto bom_byte_size(encoding_type bom) -> size_t; } // namespace BOM @@ -839,33 +835,33 @@ enum error_code { OTHER // Not related to validation/transcoding. }; -inline std::string_view error_to_string(error_code code) noexcept { - switch (code) { - case SUCCESS: - return "SUCCESS"; - case HEADER_BITS: - return "HEADER_BITS"; - case TOO_SHORT: - return "TOO_SHORT"; - case TOO_LONG: - return "TOO_LONG"; - case OVERLONG: - return "OVERLONG"; - case TOO_LARGE: - return "TOO_LARGE"; - case SURROGATE: - return "SURROGATE"; - case INVALID_BASE64_CHARACTER: - return "INVALID_BASE64_CHARACTER"; - case BASE64_INPUT_REMAINDER: - return "BASE64_INPUT_REMAINDER"; - case BASE64_EXTRA_BITS: - return "BASE64_EXTRA_BITS"; - case OUTPUT_BUFFER_TOO_SMALL: - return "OUTPUT_BUFFER_TOO_SMALL"; - default: - return "OTHER"; - } +inline auto error_to_string(error_code code) noexcept -> std::string_view { + switch (code) { + case SUCCESS: + return "SUCCESS"; + case HEADER_BITS: + return "HEADER_BITS"; + case TOO_SHORT: + return "TOO_SHORT"; + case TOO_LONG: + return "TOO_LONG"; + case OVERLONG: + return "OVERLONG"; + case TOO_LARGE: + return "TOO_LARGE"; + case SURROGATE: + return "SURROGATE"; + case INVALID_BASE64_CHARACTER: + return "INVALID_BASE64_CHARACTER"; + case BASE64_INPUT_REMAINDER: + return "BASE64_INPUT_REMAINDER"; + case BASE64_EXTRA_BITS: + return "BASE64_EXTRA_BITS"; + case OUTPUT_BUFFER_TOO_SMALL: + return "OUTPUT_BUFFER_TOO_SMALL"; + default: + return "OTHER"; + } } struct result { @@ -881,40 +877,43 @@ struct result { size_t pos) noexcept : error{err}, count{pos} {} - simdutf_really_inline simdutf_constexpr23 bool is_ok() const noexcept { - return error == error_code::SUCCESS; + [[nodiscard]] simdutf_really_inline simdutf_constexpr23 auto is_ok() const noexcept -> bool { + return error == error_code::SUCCESS; } - simdutf_really_inline simdutf_constexpr23 bool is_err() const noexcept { - return error != error_code::SUCCESS; + [[nodiscard]] simdutf_really_inline simdutf_constexpr23 auto is_err() const noexcept -> bool { + return error != error_code::SUCCESS; } }; struct full_result { error_code error; size_t input_count; - size_t output_count; - bool padding_error = false; // true if the error is due to padding, only - // meaningful when error is not SUCCESS + size_t outputCount; + bool paddingError = false; // true if the error is due to padding, only + // meaningful when error is not SUCCESS simdutf_really_inline simdutf_constexpr23 full_result() noexcept - : error{error_code::SUCCESS}, input_count{0}, output_count{0} {} - - simdutf_really_inline simdutf_constexpr23 full_result(error_code err, - size_t pos_in, - size_t pos_out) noexcept - : error{err}, input_count{pos_in}, output_count{pos_out} {} - simdutf_really_inline simdutf_constexpr23 full_result( - error_code err, size_t pos_in, size_t pos_out, bool padding_err) noexcept - : error{err}, input_count{pos_in}, output_count{pos_out}, - padding_error{padding_err} {} + : error{error_code::SUCCESS} + , input_count{0} + , outputCount{0} {} + + simdutf_really_inline simdutf_constexpr23 full_result(error_code err, size_t posIn, size_t posOut) noexcept + : error{err} + , input_count{posIn} + , outputCount{posOut} {} + simdutf_really_inline simdutf_constexpr23 full_result(error_code err, size_t posIn, size_t posOut, + bool paddingErr) noexcept + : error{err} + , input_count{posIn} + , outputCount{posOut} + , paddingError{paddingErr} {} simdutf_really_inline simdutf_constexpr23 operator result() const noexcept { if (error == error_code::SUCCESS) { - return result{error, output_count}; - } else { - return result{error, input_count}; + return result{error, outputCount}; } + return result{error, input_count}; } }; @@ -957,8 +956,8 @@ enum { /* begin file include/simdutf/implementation.h */ #ifndef SIMDUTF_IMPLEMENTATION_H #define SIMDUTF_IMPLEMENTATION_H -#if !defined(SIMDUTF_NO_THREADS) - #include +#ifndef SIMDUTF_NO_THREADS +#include #endif #ifdef SIMDUTF_INTERNAL_TESTS #include @@ -1014,8 +1013,8 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#if defined(_MSC_VER) - #include +#ifdef _MSC_VER +#include #elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) #include #endif @@ -1042,8 +1041,7 @@ struct simdutf_riscv_hwprobe { // #define HWCAP_LOONGARCH_LASX (1 << 5) #endif -namespace simdutf { -namespace internal { +namespace simdutf::internal { enum instruction_set { DEFAULT = 0x0, @@ -1070,7 +1068,7 @@ enum instruction_set { LASX = 0x80000, }; -#if defined(__PPC64__) +#ifdef __PPC64__ static inline uint32_t detect_supported_architectures() { return instruction_set::ALTIVEC; @@ -1118,152 +1116,147 @@ namespace cpuid_bit { // Can be found on Intel ISA Reference for CPUID // EAX = 0x01 -constexpr uint32_t pclmulqdq = uint32_t(1) - << 1; ///< @private bit 1 of ECX for EAX=0x1 -constexpr uint32_t sse42 = uint32_t(1) - << 20; ///< @private bit 20 of ECX for EAX=0x1 +constexpr uint32_t pclmulqdq = static_cast(1) << 1; ///< @private bit 1 of ECX for EAX=0x1 +constexpr uint32_t sse42 = static_cast(1) << 20; ///< @private bit 20 of ECX for EAX=0x1 constexpr uint32_t osxsave = - (uint32_t(1) << 26) | - (uint32_t(1) << 27); ///< @private bits 26+27 of ECX for EAX=0x1 + (static_cast(1) << 26) | (static_cast(1) << 27); ///< @private bits 26+27 of ECX for EAX=0x1 // EAX = 0x7f (Structured Extended Feature Flags), ECX = 0x00 (Sub-leaf) // See: "Table 3-8. Information Returned by CPUID Instruction" namespace ebx { -constexpr uint32_t bmi1 = uint32_t(1) << 3; -constexpr uint32_t avx2 = uint32_t(1) << 5; -constexpr uint32_t bmi2 = uint32_t(1) << 8; -constexpr uint32_t avx512f = uint32_t(1) << 16; -constexpr uint32_t avx512dq = uint32_t(1) << 17; -constexpr uint32_t avx512ifma = uint32_t(1) << 21; -constexpr uint32_t avx512cd = uint32_t(1) << 28; -constexpr uint32_t avx512bw = uint32_t(1) << 30; -constexpr uint32_t avx512vl = uint32_t(1) << 31; +constexpr uint32_t bmi1 = static_cast(1) << 3; +constexpr uint32_t avx2 = static_cast(1) << 5; +constexpr uint32_t bmi2 = static_cast(1) << 8; +constexpr uint32_t avx512f = static_cast(1) << 16; +constexpr uint32_t avx512dq = static_cast(1) << 17; +constexpr uint32_t avx512ifma = static_cast(1) << 21; +constexpr uint32_t avx512cd = static_cast(1) << 28; +constexpr uint32_t avx512bw = static_cast(1) << 30; +constexpr uint32_t avx512vl = static_cast(1) << 31; } // namespace ebx namespace ecx { -constexpr uint32_t avx512vbmi = uint32_t(1) << 1; -constexpr uint32_t avx512vbmi2 = uint32_t(1) << 6; -constexpr uint32_t avx512vnni = uint32_t(1) << 11; -constexpr uint32_t avx512bitalg = uint32_t(1) << 12; -constexpr uint32_t avx512vpopcnt = uint32_t(1) << 14; +constexpr uint32_t avx512vbmi = static_cast(1) << 1; +constexpr uint32_t avx512vbmi2 = static_cast(1) << 6; +constexpr uint32_t avx512vnni = static_cast(1) << 11; +constexpr uint32_t avx512bitalg = static_cast(1) << 12; +constexpr uint32_t avx512vpopcnt = static_cast(1) << 14; } // namespace ecx namespace edx { -constexpr uint32_t avx512vp2intersect = uint32_t(1) << 8; +constexpr uint32_t avx512vp2intersect = static_cast(1) << 8; } namespace xcr0_bit { -constexpr uint64_t avx256_saved = uint64_t(1) << 2; ///< @private bit 2 = AVX -constexpr uint64_t avx512_saved = - uint64_t(7) << 5; ///< @private bits 5,6,7 = opmask, ZMM_hi256, hi16_ZMM +constexpr uint64_t avx256Saved = static_cast(1) << 2; ///< @private bit 2 = AVX +constexpr uint64_t avx512Saved = static_cast(7) << 5; ///< @private bits 5,6,7 = opmask, ZMM_hi256, hi16_ZMM } // namespace xcr0_bit } // namespace cpuid_bit } // namespace static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { - #if defined(_MSC_VER) - int cpu_info[4]; - __cpuidex(cpu_info, *eax, *ecx); - *eax = cpu_info[0]; - *ebx = cpu_info[1]; - *ecx = cpu_info[2]; - *edx = cpu_info[3]; - #elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) - uint32_t level = *eax; - __get_cpuid(level, eax, ebx, ecx, edx); - #else - uint32_t a = *eax, b, c = *ecx, d; - asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); - *eax = a; - *ebx = b; - *ecx = c; - *edx = d; - #endif +#ifdef _MSC_VER + int cpuInfo[4]; + __cpuidex(cpuInfo, *eax, *ecx); + *eax = cpuInfo[0]; + *ebx = cpuInfo[1]; + *ecx = cpuInfo[2]; + *edx = cpuInfo[3]; +#elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) + uint32_t level = *eax; + __get_cpuid(level, eax, ebx, ecx, edx); +#else + uint32_t a = *eax, b, c = *ecx, d; + asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); + *eax = a; + *ebx = b; + *ecx = c; + *edx = d; +#endif } -static inline uint64_t xgetbv() { - #if defined(_MSC_VER) - return _xgetbv(0); - #else - uint32_t xcr0_lo, xcr0_hi; - asm volatile("xgetbv\n\t" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0)); - return xcr0_lo | ((uint64_t)xcr0_hi << 32); - #endif +static inline auto xgetbv() -> uint64_t { +#ifdef _MSC_VER + return _xgetbv(0); +#else + uint32_t xcr0_lo, xcr0_hi; + asm volatile("xgetbv\n\t" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0)); + return xcr0_lo | ((uint64_t)xcr0_hi << 32); +#endif } -static inline uint32_t detect_supported_architectures() { - uint32_t eax; - uint32_t ebx = 0; - uint32_t ecx = 0; - uint32_t edx = 0; - uint32_t host_isa = 0x0; +static inline auto detect_supported_architectures() -> uint32_t { + uint32_t eax = 0; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + uint32_t hostIsa = 0x0; - // EBX for EAX=0x1 - eax = 0x1; - cpuid(&eax, &ebx, &ecx, &edx); + // EBX for EAX=0x1 + eax = 0x1; + cpuid(&eax, &ebx, &ecx, &edx); - if (ecx & cpuid_bit::sse42) { - host_isa |= instruction_set::SSE42; - } + if ((ecx & cpuid_bit::sse42) != 0u) { + hostIsa |= instruction_set::SSE42; + } - if (ecx & cpuid_bit::pclmulqdq) { - host_isa |= instruction_set::PCLMULQDQ; - } + if ((ecx & cpuid_bit::pclmulqdq) != 0u) { + hostIsa |= instruction_set::PCLMULQDQ; + } - if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) { - return host_isa; - } + if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) { + return hostIsa; + } - // xgetbv for checking if the OS saves registers - uint64_t xcr0 = xgetbv(); + // xgetbv for checking if the OS saves registers + uint64_t xcr0 = xgetbv(); - if ((xcr0 & cpuid_bit::xcr0_bit::avx256_saved) == 0) { - return host_isa; - } - // ECX for EAX=0x7 - eax = 0x7; - ecx = 0x0; // Sub-leaf = 0 - cpuid(&eax, &ebx, &ecx, &edx); - if (ebx & cpuid_bit::ebx::avx2) { - host_isa |= instruction_set::AVX2; - } - if (ebx & cpuid_bit::ebx::bmi1) { - host_isa |= instruction_set::BMI1; - } - if (ebx & cpuid_bit::ebx::bmi2) { - host_isa |= instruction_set::BMI2; - } - if (!((xcr0 & cpuid_bit::xcr0_bit::avx512_saved) == - cpuid_bit::xcr0_bit::avx512_saved)) { - return host_isa; - } - if (ebx & cpuid_bit::ebx::avx512f) { - host_isa |= instruction_set::AVX512F; - } - if (ebx & cpuid_bit::ebx::avx512bw) { - host_isa |= instruction_set::AVX512BW; - } - if (ebx & cpuid_bit::ebx::avx512cd) { - host_isa |= instruction_set::AVX512CD; - } - if (ebx & cpuid_bit::ebx::avx512dq) { - host_isa |= instruction_set::AVX512DQ; - } - if (ebx & cpuid_bit::ebx::avx512vl) { - host_isa |= instruction_set::AVX512VL; - } - if (ecx & cpuid_bit::ecx::avx512vbmi2) { - host_isa |= instruction_set::AVX512VBMI2; - } - if (ecx & cpuid_bit::ecx::avx512vpopcnt) { - host_isa |= instruction_set::AVX512VPOPCNTDQ; - } - return host_isa; + if ((xcr0 & cpuid_bit::xcr0_bit::avx256Saved) == 0) { + return hostIsa; + } + // ECX for EAX=0x7 + eax = 0x7; + ecx = 0x0; // Sub-leaf = 0 + cpuid(&eax, &ebx, &ecx, &edx); + if ((ebx & cpuid_bit::ebx::avx2) != 0u) { + hostIsa |= instruction_set::AVX2; + } + if ((ebx & cpuid_bit::ebx::bmi1) != 0u) { + hostIsa |= instruction_set::BMI1; + } + if ((ebx & cpuid_bit::ebx::bmi2) != 0u) { + hostIsa |= instruction_set::BMI2; + } + if (!((xcr0 & cpuid_bit::xcr0_bit::avx512Saved) == cpuid_bit::xcr0_bit::avx512Saved)) { + return hostIsa; + } + if ((ebx & cpuid_bit::ebx::avx512f) != 0u) { + hostIsa |= instruction_set::AVX512F; + } + if ((ebx & cpuid_bit::ebx::avx512bw) != 0u) { + hostIsa |= instruction_set::AVX512BW; + } + if ((ebx & cpuid_bit::ebx::avx512cd) != 0u) { + hostIsa |= instruction_set::AVX512CD; + } + if ((ebx & cpuid_bit::ebx::avx512dq) != 0u) { + hostIsa |= instruction_set::AVX512DQ; + } + if ((ebx & cpuid_bit::ebx::avx512vl) != 0u) { + hostIsa |= instruction_set::AVX512VL; + } + if ((ecx & cpuid_bit::ecx::avx512vbmi2) != 0u) { + hostIsa |= instruction_set::AVX512VBMI2; + } + if ((ecx & cpuid_bit::ecx::avx512vpopcnt) != 0u) { + hostIsa |= instruction_set::AVX512VPOPCNTDQ; + } + return hostIsa; } -#elif defined(__loongarch__) +#elifdef __loongarch__ static inline uint32_t detect_supported_architectures() { uint32_t host_isa = instruction_set::DEFAULT; - #if defined(__linux__) +#if defined(__linux__) uint64_t hwcap = 0; hwcap = getauxval(AT_HWCAP); if (hwcap & HWCAP_LOONGARCH_LSX) { @@ -1272,7 +1265,7 @@ static inline uint32_t detect_supported_architectures() { if (hwcap & HWCAP_LOONGARCH_LASX) { host_isa |= instruction_set::LASX; } - #endif +#endif return host_isa; } #else // fallback @@ -1284,8 +1277,7 @@ static inline uint32_t detect_supported_architectures() { #endif // end SIMD extension detection code -} // namespace internal -} // namespace simdutf +} // namespace simdutf::internal #endif // SIMDutf_INTERNAL_ISADETECTION_H /* end file include/simdutf/internal/isadetection.h */ @@ -1336,8 +1328,7 @@ static inline uint32_t detect_supported_architectures() { #include -namespace simdutf { -namespace detail { +namespace simdutf::detail { /** * The constexpr_ptr class is a workaround for reinterpret_cast not being * allowed during constant evaluation. @@ -1349,54 +1340,56 @@ struct constexpr_ptr { constexpr explicit constexpr_ptr(const from *ptr) noexcept : p(ptr) {} - constexpr to operator*() const noexcept { return static_cast(*p); } + constexpr auto operator*() const noexcept -> to { + return static_cast(*p); + } - constexpr constexpr_ptr &operator++() noexcept { - ++p; - return *this; + constexpr auto operator++() noexcept -> constexpr_ptr& { + ++p; + return *this; } - constexpr constexpr_ptr operator++(int) noexcept { - auto old = *this; - ++p; - return old; + constexpr auto operator++(int) noexcept -> constexpr_ptr { + auto old = *this; + ++p; + return old; } - constexpr constexpr_ptr &operator--() noexcept { - --p; - return *this; + constexpr auto operator--() noexcept -> constexpr_ptr& { + --p; + return *this; } - constexpr constexpr_ptr operator--(int) noexcept { - auto old = *this; - --p; - return old; + constexpr auto operator--(int) noexcept -> constexpr_ptr { + auto old = *this; + --p; + return old; } - constexpr constexpr_ptr &operator+=(std::ptrdiff_t n) noexcept { - p += n; - return *this; + constexpr auto operator+=(std::ptrdiff_t n) noexcept -> constexpr_ptr& { + p += n; + return *this; } - constexpr constexpr_ptr &operator-=(std::ptrdiff_t n) noexcept { - p -= n; - return *this; + constexpr auto operator-=(std::ptrdiff_t n) noexcept -> constexpr_ptr& { + p -= n; + return *this; } - constexpr constexpr_ptr operator+(std::ptrdiff_t n) const noexcept { - return constexpr_ptr{p + n}; + constexpr auto operator+(std::ptrdiff_t n) const noexcept -> constexpr_ptr { + return constexpr_ptr{p + n}; } - constexpr constexpr_ptr operator-(std::ptrdiff_t n) const noexcept { - return constexpr_ptr{p - n}; + constexpr auto operator-(std::ptrdiff_t n) const noexcept -> constexpr_ptr { + return constexpr_ptr{p - n}; } - constexpr std::ptrdiff_t operator-(const constexpr_ptr &o) const noexcept { - return p - o.p; + constexpr auto operator-(const constexpr_ptr& o) const noexcept -> std::ptrdiff_t { + return p - o.p; } - constexpr to operator[](std::ptrdiff_t n) const noexcept { - return static_cast(*(p + n)); + constexpr auto operator[](std::ptrdiff_t n) const noexcept -> to { + return static_cast(*(p + n)); } // to prevent compilation errors for memcpy, even if it is never @@ -1404,9 +1397,8 @@ struct constexpr_ptr { constexpr operator const void *() const noexcept { return p; } }; -template -constexpr constexpr_ptr constexpr_cast_ptr(from *p) noexcept { - return constexpr_ptr{p}; +template constexpr auto constexpr_cast_ptr(from* p) noexcept -> constexpr_ptr { + return constexpr_ptr{p}; } /** @@ -1418,9 +1410,9 @@ struct constexpr_write_ptr_proxy { constexpr explicit constexpr_write_ptr_proxy(TargetType *raw) : p(raw) {} - constexpr constexpr_write_ptr_proxy &operator=(SrcType v) { - *p = static_cast(v); - return *this; + constexpr auto operator=(SrcType v) -> constexpr_write_ptr_proxy& { + *p = static_cast(v); + return *this; } TargetType *p; @@ -1434,28 +1426,27 @@ struct constexpr_write_ptr_proxy { template struct constexpr_write_ptr { constexpr explicit constexpr_write_ptr(TargetType *raw) : p(raw) {} - constexpr constexpr_write_ptr_proxy operator*() const { - return constexpr_write_ptr_proxy{p}; + constexpr auto operator*() const -> constexpr_write_ptr_proxy { + return constexpr_write_ptr_proxy{p}; } - constexpr constexpr_write_ptr_proxy - operator[](std::ptrdiff_t n) const { - return constexpr_write_ptr_proxy{p + n}; + constexpr auto operator[](std::ptrdiff_t n) const -> constexpr_write_ptr_proxy { + return constexpr_write_ptr_proxy{p + n}; } - constexpr constexpr_write_ptr &operator++() { - ++p; - return *this; + constexpr auto operator++() -> constexpr_write_ptr& { + ++p; + return *this; } - constexpr constexpr_write_ptr operator++(int) { - constexpr_write_ptr old = *this; - ++p; - return old; + constexpr auto operator++(int) -> constexpr_write_ptr { + constexpr_write_ptr old = *this; + ++p; + return old; } - constexpr std::ptrdiff_t operator-(const constexpr_write_ptr &other) const { - return p - other.p; + constexpr auto operator-(const constexpr_write_ptr& other) const -> std::ptrdiff_t { + return p - other.p; } TargetType *p; @@ -1466,16 +1457,16 @@ constexpr auto constexpr_cast_writeptr(TargetType *raw) { return constexpr_write_ptr{raw}; } -} // namespace detail -} // namespace simdutf +} // namespace simdutf::detail + #endif /* end file include/simdutf/constexpr_ptr.h */ #endif #if SIMDUTF_SPAN /// helpers placed in namespace detail are not a part of the public API -namespace simdutf { -namespace detail { + +namespace simdutf::detail { /** * matches a byte, in the many ways C++ allows. note that these * are all distinct types. @@ -1550,8 +1541,8 @@ template concept indexes_into_uint32 = requires(InputPtr p) { { std::decay_t{} } -> std::same_as; }; -} // namespace detail -} // namespace simdutf +} // namespace simdutf::detail + #endif // SIMDUTF_SPAN // these includes are needed for constexpr support. they are @@ -1560,36 +1551,32 @@ concept indexes_into_uint32 = requires(InputPtr p) { #ifndef SIMDUTF_SWAP_BYTES_H #define SIMDUTF_SWAP_BYTES_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { -constexpr inline simdutf_warn_unused uint16_t -u16_swap_bytes(const uint16_t word) { - return uint16_t((word >> 8) | (word << 8)); +constexpr simdutf_warn_unused auto u16_swap_bytes(const uint16_t word) -> uint16_t { + return static_cast((word >> 8) | (word << 8)); } -constexpr inline simdutf_warn_unused uint32_t -u32_swap_bytes(const uint32_t word) { - return ((word >> 24) & 0xff) | // move byte 3 to byte 0 - ((word << 8) & 0xff0000) | // move byte 1 to byte 2 - ((word >> 8) & 0xff00) | // move byte 2 to byte 1 - ((word << 24) & 0xff000000); // byte 0 to byte 3 +constexpr simdutf_warn_unused auto u32_swap_bytes(const uint32_t word) -> uint32_t { + return ((word >> 24) & 0xff) | // move byte 3 to byte 0 + ((word << 8) & 0xff0000) | // move byte 1 to byte 2 + ((word >> 8) & 0xff00) | // move byte 2 to byte 1 + ((word << 24) & 0xff000000); // byte 0 to byte 3 } namespace utf32 { -template constexpr uint32_t swap_if_needed(uint32_t c) { - return !match_system(big_endian) ? scalar::u32_swap_bytes(c) : c; +template constexpr auto swap_if_needed(uint32_t c) -> uint32_t { + return !match_system(big_endian) ? scalar::u32_swap_bytes(c) : c; } } // namespace utf32 namespace utf16 { -template constexpr uint16_t swap_if_needed(uint16_t c) { - return !match_system(big_endian) ? scalar::u16_swap_bytes(c) : c; +template constexpr auto swap_if_needed(uint16_t c) -> uint16_t { + return !match_system(big_endian) ? scalar::u16_swap_bytes(c) : c; } } // namespace utf16 -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/swap_bytes.h */ @@ -1597,17 +1584,15 @@ template constexpr uint16_t swap_if_needed(uint16_t c) { #ifndef SIMDUTF_ASCII_H #define SIMDUTF_ASCII_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace ascii { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, - size_t len) noexcept { +simdutf_warn_unused simdutf_constexpr23 auto validate(InputPtr data, size_t len) noexcept -> bool { uint64_t pos = 0; #if SIMDUTF_CPLUSPLUS23 @@ -1617,14 +1602,14 @@ simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, // process in blocks of 16 bytes when possible { for (; pos + 16 <= len; pos += 16) { - uint64_t v1; - std::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) != 0) { - return false; - } + uint64_t v1 = 0; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) != 0) { + return false; + } } } @@ -1638,10 +1623,9 @@ simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_warn_unused simdutf_constexpr23 result -validate_with_errors(InputPtr data, size_t len) noexcept { +simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(InputPtr data, size_t len) noexcept -> result { size_t pos = 0; #if SIMDUTF_CPLUSPLUS23 // avoid memcpy during constant evaluation @@ -1650,17 +1634,17 @@ validate_with_errors(InputPtr data, size_t len) noexcept { { // process in blocks of 16 bytes when possible for (; pos + 16 <= len; pos += 16) { - uint64_t v1; - std::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) != 0) { - for (; pos < len; pos++) { - if (static_cast(data[pos]) >= 0b10000000) { - return result(error_code::TOO_LARGE, pos); - } - } + uint64_t v1 = 0; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) != 0) { + for (; pos < len; pos++) { + if (static_cast(data[pos]) >= 0b10000000) { + return {error_code::TOO_LARGE, pos}; + } + } } } } @@ -1668,16 +1652,15 @@ validate_with_errors(InputPtr data, size_t len) noexcept { // process the tail byte-by-byte for (; pos < len; pos++) { if (static_cast(data[pos]) >= 0b10000000) { - return result(error_code::TOO_LARGE, pos); + return {error_code::TOO_LARGE, pos}; } } - return result(error_code::SUCCESS, pos); + return {error_code::SUCCESS, pos}; } } // namespace ascii } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/ascii.h */ @@ -1686,8 +1669,8 @@ validate_with_errors(InputPtr data, size_t len) noexcept { #define SIMDUTF_ATOMIC_UTIL_H #if SIMDUTF_ATOMIC_REF #include -namespace simdutf { -namespace scalar { + +namespace simdutf::scalar { // This function is a memcpy that uses atomic operations to read from the // source. @@ -1700,39 +1683,36 @@ inline void memcpy_atomic_read(char *dst, const char *src, size_t len) { constexpr size_t alignment = sizeof(uint64_t); // Lambda for atomic byte-by-byte copy - auto bbb_memcpy_atomic_read = [](char *bytedst, const char *bytesrc, - size_t bytelen) noexcept { - char *mutable_src = const_cast(bytesrc); - for (size_t j = 0; j < bytelen; ++j) { - bytedst[j] = - std::atomic_ref(mutable_src[j]).load(std::memory_order_relaxed); - } + auto bbbMemcpyAtomicRead = [](char* bytedst, const char* bytesrc, size_t bytelen) noexcept -> void { + char* mutableSrc = const_cast(bytesrc); + for (size_t j = 0; j < bytelen; ++j) { + bytedst[j] = std::atomic_ref(mutableSrc[j]).load(std::memory_order_relaxed); + } }; // Handle unaligned start size_t offset = reinterpret_cast(src) % alignment; - if (offset) { - size_t to_align = std::min(len, alignment - offset); - bbb_memcpy_atomic_read(dst, src, to_align); - src += to_align; - dst += to_align; - len -= to_align; + if (offset != 0u) { + size_t toAlign = std::min(len, alignment - offset); + bbbMemcpyAtomicRead(dst, src, toAlign); + src += toAlign; + dst += toAlign; + len -= toAlign; } // Process aligned 64-bit chunks while (len >= alignment) { - auto *src_aligned = reinterpret_cast(const_cast(src)); - const auto dst_value = - std::atomic_ref(*src_aligned).load(std::memory_order_relaxed); - std::memcpy(dst, &dst_value, sizeof(uint64_t)); - src += alignment; - dst += alignment; - len -= alignment; + auto* srcAligned = reinterpret_cast(const_cast(src)); + const auto dstValue = std::atomic_ref(*srcAligned).load(std::memory_order_relaxed); + std::memcpy(dst, &dstValue, sizeof(uint64_t)); + src += alignment; + dst += alignment; + len -= alignment; } // Handle remaining bytes - if (len) { - bbb_memcpy_atomic_read(dst, src, len); + if (len != 0u) { + bbbMemcpyAtomicRead(dst, src, len); } } @@ -1748,43 +1728,40 @@ inline void memcpy_atomic_write(char *dst, const char *src, size_t len) { constexpr size_t alignment = sizeof(uint64_t); // Lambda for atomic byte-by-byte write - auto bbb_memcpy_atomic_write = [](char *bytedst, const char *bytesrc, - size_t bytelen) noexcept { - for (size_t j = 0; j < bytelen; ++j) { - std::atomic_ref(bytedst[j]) - .store(bytesrc[j], std::memory_order_relaxed); - } + auto bbbMemcpyAtomicWrite = [](char* bytedst, const char* bytesrc, size_t bytelen) noexcept -> void { + for (size_t j = 0; j < bytelen; ++j) { + std::atomic_ref(bytedst[j]).store(bytesrc[j], std::memory_order_relaxed); + } }; // Handle unaligned start size_t offset = reinterpret_cast(dst) % alignment; - if (offset) { - size_t to_align = std::min(len, alignment - offset); - bbb_memcpy_atomic_write(dst, src, to_align); - dst += to_align; - src += to_align; - len -= to_align; + if (offset != 0u) { + size_t toAlign = std::min(len, alignment - offset); + bbbMemcpyAtomicWrite(dst, src, toAlign); + dst += toAlign; + src += toAlign; + len -= toAlign; } // Process aligned 64-bit chunks while (len >= alignment) { - auto *dst_aligned = reinterpret_cast(dst); - uint64_t src_val; - std::memcpy(&src_val, src, sizeof(uint64_t)); // Non-atomic read from src - std::atomic_ref(*dst_aligned) - .store(src_val, std::memory_order_relaxed); - dst += alignment; - src += alignment; - len -= alignment; + auto* dstAligned = reinterpret_cast(dst); + uint64_t srcVal = 0; + std::memcpy(&srcVal, src, sizeof(uint64_t)); // Non-atomic read from src + std::atomic_ref(*dstAligned).store(srcVal, std::memory_order_relaxed); + dst += alignment; + src += alignment; + len -= alignment; } // Handle remaining bytes - if (len) { - bbb_memcpy_atomic_write(dst, src, len); + if (len != 0u) { + bbbMemcpyAtomicWrite(dst, src, len); } } -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar + #endif // SIMDUTF_ATOMIC_REF #endif // SIMDUTF_ATOMIC_UTIL_H /* end file include/simdutf/scalar/atomic_util.h */ @@ -1792,27 +1769,24 @@ inline void memcpy_atomic_write(char *dst, const char *src, size_t len) { #ifndef SIMDUTF_LATIN1_H #define SIMDUTF_LATIN1_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace latin1 { -simdutf_really_inline size_t utf8_length_from_latin1(const char *buf, - size_t len) { - const uint8_t *c = reinterpret_cast(buf); - size_t answer = 0; - for (size_t i = 0; i < len; i++) { - if ((c[i] >> 7)) { - answer++; +simdutf_really_inline auto utf8_length_from_latin1(const char* buf, size_t len) -> size_t { + const auto* c = reinterpret_cast(buf); + size_t answer = 0; + for (size_t i = 0; i < len; i++) { + if ((c[i] >> 7) != 0) { + answer++; + } } - } - return answer + len; + return answer + len; } } // namespace latin1 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/latin1.h */ @@ -1820,53 +1794,46 @@ simdutf_really_inline size_t utf8_length_from_latin1(const char *buf, #ifndef SIMDUTF_LATIN1_TO_UTF16_H #define SIMDUTF_LATIN1_TO_UTF16_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace latin1_to_utf16 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - char16_t *utf16_output) { +simdutf_constexpr23 auto convert(InputPtr data, size_t len, char16_t* utf16Output) -> size_t { size_t pos = 0; - char16_t *start{utf16_output}; + char16_t* start{utf16Output}; while (pos < len) { uint16_t word = uint8_t(data[pos]); // extend Latin-1 char to 16-bit Unicode code point - *utf16_output++ = - char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); + *utf16Output++ = char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); pos++; } - return utf16_output - start; + return utf16Output - start; } template -inline result convert_with_errors(const char *buf, size_t len, - char16_t *utf16_output) { - const uint8_t *data = reinterpret_cast(buf); - size_t pos = 0; - char16_t *start{utf16_output}; - - while (pos < len) { - uint16_t word = - uint16_t(data[pos]); // extend Latin-1 char to 16-bit Unicode code point - *utf16_output++ = - char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); - pos++; - } +inline auto convert_with_errors(const char* buf, size_t len, char16_t* utf16Output) -> result { + const auto* data = reinterpret_cast(buf); + size_t pos = 0; + char16_t* start{utf16Output}; + + while (pos < len) { + auto word = static_cast(data[pos]); // extend Latin-1 char to 16-bit Unicode code point + *utf16Output++ = char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); + pos++; + } - return result(error_code::SUCCESS, utf16_output - start); + return {error_code::SUCCESS, utf16Output - start}; } } // namespace latin1_to_utf16 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/latin1_to_utf16/latin1_to_utf16.h */ @@ -1874,28 +1841,25 @@ inline result convert_with_errors(const char *buf, size_t len, #ifndef SIMDUTF_LATIN1_TO_UTF32_H #define SIMDUTF_LATIN1_TO_UTF32_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace latin1_to_utf32 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - char32_t *utf32_output) { - char32_t *start{utf32_output}; - for (size_t i = 0; i < len; i++) { - *utf32_output++ = uint8_t(data[i]); - } - return utf32_output - start; +simdutf_constexpr23 auto convert(InputPtr data, size_t len, char32_t* utf32Output) -> size_t { + char32_t* start{utf32Output}; + for (size_t i = 0; i < len; i++) { + *utf32Output++ = uint8_t(data[i]); + } + return utf32Output - start; } } // namespace latin1_to_utf32 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/latin1_to_utf32/latin1_to_utf32.h */ @@ -1903,21 +1867,19 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, #ifndef SIMDUTF_LATIN1_TO_UTF8_H #define SIMDUTF_LATIN1_TO_UTF8_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace latin1_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_byte_like && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_byte_like && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - OutputPtr utf8_output) { +simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { // const unsigned char *data = reinterpret_cast(buf); size_t pos = 0; - size_t utf8_pos = 0; + size_t utf8Pos = 0; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -1927,129 +1889,120 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | - v2}; // We are only interested in these bits: 1000 1000 1000 - // 1000, so it makes sense to concatenate everything - if ((v & 0x8080808080808080) == - 0) { // if NONE of these are set, e.g. all of them are zero, then - // everything is ASCII - size_t final_pos = pos + 16; - while (pos < final_pos) { - utf8_output[utf8_pos++] = char(data[pos]); - pos++; - } - continue; - } + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 1000 + // 1000, so it makes sense to concatenate everything + if ((v & 0x8080808080808080) == + 0) { // if NONE of these are set, e.g. all of them are zero, then + // everything is ASCII + size_t finalPos = pos + 16; + while (pos < finalPos) { + utf8Output[utf8Pos++] = char(data[pos]); + pos++; + } + continue; + } } // if (pos + 16 <= len) } // !consteval scope unsigned char byte = data[pos]; if ((byte & 0x80) == 0) { // if ASCII // will generate one UTF-8 bytes - utf8_output[utf8_pos++] = char(byte); + utf8Output[utf8Pos++] = static_cast(byte); pos++; } else { // will generate two UTF-8 bytes - utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); - utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); + utf8Output[utf8Pos++] = static_cast((byte >> 6) | 0b11000000); + utf8Output[utf8Pos++] = static_cast((byte & 0b111111) | 0b10000000); pos++; } } // while - return utf8_pos; -} - -simdutf_really_inline size_t convert(const char *buf, size_t len, - char *utf8_output) { - return convert(reinterpret_cast(buf), len, - utf8_output); -} - -inline size_t convert_safe(const char *buf, size_t len, char *utf8_output, - size_t utf8_len) { - const unsigned char *data = reinterpret_cast(buf); - size_t pos = 0; - size_t skip_pos = 0; - size_t utf8_pos = 0; - while (pos < len && utf8_pos < utf8_len) { - // try to convert the next block of 16 ASCII bytes - if (pos >= skip_pos && pos + 16 <= len && - utf8_pos + 16 <= utf8_len) { // if it is safe to read 16 more bytes, - // check that they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | - v2}; // We are only interested in these bits: 1000 1000 1000 - // 1000, so it makes sense to concatenate everything - if ((v & 0x8080808080808080) == - 0) { // if NONE of these are set, e.g. all of them are zero, then - // everything is ASCII - ::memcpy(utf8_output + utf8_pos, buf + pos, 16); - utf8_pos += 16; - pos += 16; - } else { - // At least one of the next 16 bytes are not ASCII, we will process them - // one by one - skip_pos = pos + 16; - } - } else { - const auto byte = data[pos]; - if ((byte & 0x80) == 0) { // if ASCII - // will generate one UTF-8 bytes - utf8_output[utf8_pos++] = char(byte); - pos++; - } else if (utf8_pos + 2 <= utf8_len) { - // will generate two UTF-8 bytes - utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); - utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); - pos++; - } else { - break; - } + return utf8Pos; +} + +simdutf_really_inline auto convert(const char* buf, size_t len, char* utf8Output) -> size_t { + return convert(reinterpret_cast(buf), len, utf8Output); +} + +inline auto convert_safe(const char* buf, size_t len, char* utf8Output, size_t utf8Len) -> size_t { + const auto* data = reinterpret_cast(buf); + size_t pos = 0; + size_t skipPos = 0; + size_t utf8Pos = 0; + while (pos < len && utf8Pos < utf8Len) { + // try to convert the next block of 16 ASCII bytes + if (pos >= skipPos && pos + 16 <= len && utf8Pos + 16 <= utf8Len) { // if it is safe to read 16 more bytes, + // check that they are ascii + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 1000 + // 1000, so it makes sense to concatenate everything + if ((v & 0x8080808080808080) == 0) { // if NONE of these are set, e.g. all of them are zero, then + // everything is ASCII + ::memcpy(utf8Output + utf8Pos, buf + pos, 16); + utf8Pos += 16; + pos += 16; + } else { + // At least one of the next 16 bytes are not ASCII, we will process them + // one by one + skipPos = pos + 16; + } + } else { + const auto byte = data[pos]; + if ((byte & 0x80) == 0) { // if ASCII + // will generate one UTF-8 bytes + utf8Output[utf8Pos++] = static_cast(byte); + pos++; + } else if (utf8Pos + 2 <= utf8Len) { + // will generate two UTF-8 bytes + utf8Output[utf8Pos++] = static_cast((byte >> 6) | 0b11000000); + utf8Output[utf8Pos++] = static_cast((byte & 0b111111) | 0b10000000); + pos++; + } else { + break; + } + } } - } - return utf8_pos; + return utf8Pos; } template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_byte_like && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_byte_like && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 size_t convert_safe_constexpr(InputPtr data, size_t len, - OutputPtr utf8_output, - size_t utf8_len) { +simdutf_constexpr23 auto convert_safe_constexpr(InputPtr data, size_t len, OutputPtr utf8Output, size_t utf8Len) + -> size_t { size_t pos = 0; - size_t utf8_pos = 0; - while (pos < len && utf8_pos < utf8_len) { - const unsigned char byte = data[pos]; - if ((byte & 0x80) == 0) { // if ASCII - // will generate one UTF-8 bytes - utf8_output[utf8_pos++] = char(byte); - pos++; - } else if (utf8_pos + 2 <= utf8_len) { - // will generate two UTF-8 bytes - utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); - utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); - pos++; - } else { - break; - } + size_t utf8Pos = 0; + while (pos < len && utf8Pos < utf8Len) { + const unsigned char byte = data[pos]; + if ((byte & 0x80) == 0) { // if ASCII + // will generate one UTF-8 bytes + utf8Output[utf8Pos++] = char(byte); + pos++; + } else if (utf8Pos + 2 <= utf8Len) { + // will generate two UTF-8 bytes + utf8Output[utf8Pos++] = char((byte >> 6) | 0b11000000); + utf8Output[utf8Pos++] = char((byte & 0b111111) | 0b10000000); + pos++; + } else { + break; + } } - return utf8_pos; + return utf8Pos; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 simdutf_warn_unused size_t -utf8_length_from_latin1(InputPtr input, size_t length) noexcept { +simdutf_constexpr23 simdutf_warn_unused auto utf8_length_from_latin1(InputPtr input, size_t length) noexcept -> size_t { size_t answer = length; size_t i = 0; @@ -2057,26 +2010,24 @@ utf8_length_from_latin1(InputPtr input, size_t length) noexcept { if !consteval #endif { - auto pop = [](uint64_t v) { - return (size_t)(((v >> 7) & UINT64_C(0x0101010101010101)) * - UINT64_C(0x0101010101010101) >> - 56); - }; - for (; i + 32 <= length; i += 32) { - uint64_t v; - memcpy(&v, input + i, 8); - answer += pop(v); - memcpy(&v, input + i + 8, sizeof(v)); - answer += pop(v); - memcpy(&v, input + i + 16, sizeof(v)); - answer += pop(v); - memcpy(&v, input + i + 24, sizeof(v)); - answer += pop(v); - } + auto pop = [](uint64_t v) -> auto { + return static_cast(((v >> 7) & UINT64_C(0x0101010101010101)) * UINT64_C(0x0101010101010101) >> 56); + }; + for (; i + 32 <= length; i += 32) { + uint64_t v = 0; + memcpy(&v, input + i, 8); + answer += pop(v); + memcpy(&v, input + i + 8, sizeof(v)); + answer += pop(v); + memcpy(&v, input + i + 16, sizeof(v)); + answer += pop(v); + memcpy(&v, input + i + 24, sizeof(v)); + answer += pop(v); + } for (; i + 8 <= length; i += 8) { - uint64_t v; - memcpy(&v, input + i, sizeof(v)); - answer += pop(v); + uint64_t v = 0; + memcpy(&v, input + i, sizeof(v)); + answer += pop(v); } } // !consteval scope for (; i + 1 <= length; i += 1) { @@ -2087,8 +2038,7 @@ utf8_length_from_latin1(InputPtr input, size_t length) noexcept { } // namespace latin1_to_utf8 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/latin1_to_utf8/latin1_to_utf8.h */ @@ -2096,199 +2046,183 @@ utf8_length_from_latin1(InputPtr input, size_t length) noexcept { #ifndef SIMDUTF_UTF16_H #define SIMDUTF_UTF16_H -namespace simdutf { -namespace scalar { -namespace utf16 { +namespace simdutf::scalar::utf16 { template -simdutf_warn_unused simdutf_constexpr23 bool -validate_as_ascii(const char16_t *data, size_t len) noexcept { - for (size_t pos = 0; pos < len; pos++) { - char16_t word = scalar::utf16::swap_if_needed(data[pos]); - if (word >= 0x80) { - return false; +simdutf_warn_unused simdutf_constexpr23 auto validate_as_ascii(const char16_t* data, size_t len) noexcept -> bool { + for (size_t pos = 0; pos < len; pos++) { + char16_t word = scalar::utf16::swap_if_needed(data[pos]); + if (word >= 0x80) { + return false; + } } - } - return true; + return true; } template -inline simdutf_warn_unused simdutf_constexpr23 bool -validate(const char16_t *data, size_t len) noexcept { - uint64_t pos = 0; - while (pos < len) { - char16_t word = scalar::utf16::swap_if_needed(data[pos]); - if ((word & 0xF800) == 0xD800) { - if (pos + 1 >= len) { - return false; - } - char16_t diff = char16_t(word - 0xD800); - if (diff > 0x3FF) { - return false; - } - char16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - char16_t diff2 = char16_t(next_word - 0xDC00); - if (diff2 > 0x3FF) { - return false; - } - pos += 2; - } else { - pos++; +simdutf_warn_unused simdutf_constexpr23 auto validate(const char16_t* data, size_t len) noexcept -> bool { + uint64_t pos = 0; + while (pos < len) { + char16_t word = scalar::utf16::swap_if_needed(data[pos]); + if ((word & 0xF800) == 0xD800) { + if (pos + 1 >= len) { + return false; + } + auto diff = static_cast(word - 0xD800); + if (diff > 0x3FF) { + return false; + } + char16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + auto diff2 = static_cast(nextWord - 0xDC00); + if (diff2 > 0x3FF) { + return false; + } + pos += 2; + } else { + pos++; + } } - } - return true; + return true; } template -inline simdutf_warn_unused simdutf_constexpr23 result -validate_with_errors(const char16_t *data, size_t len) noexcept { - size_t pos = 0; - while (pos < len) { - char16_t word = scalar::utf16::swap_if_needed(data[pos]); - if ((word & 0xF800) == 0xD800) { - if (pos + 1 >= len) { - return result(error_code::SURROGATE, pos); - } - char16_t diff = char16_t(word - 0xD800); - if (diff > 0x3FF) { - return result(error_code::SURROGATE, pos); - } - char16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - char16_t diff2 = uint16_t(next_word - 0xDC00); - if (diff2 > 0x3FF) { - return result(error_code::SURROGATE, pos); - } - pos += 2; - } else { - pos++; +simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(const char16_t* data, size_t len) noexcept -> result { + size_t pos = 0; + while (pos < len) { + char16_t word = scalar::utf16::swap_if_needed(data[pos]); + if ((word & 0xF800) == 0xD800) { + if (pos + 1 >= len) { + return {error_code::SURROGATE, pos}; + } + auto diff = static_cast(word - 0xD800); + if (diff > 0x3FF) { + return {error_code::SURROGATE, pos}; + } + char16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + char16_t diff2 = static_cast(nextWord - 0xDC00); + if (diff2 > 0x3FF) { + return {error_code::SURROGATE, pos}; + } + pos += 2; + } else { + pos++; + } } - } - return result(error_code::SUCCESS, pos); + return {error_code::SUCCESS, pos}; } -template -simdutf_constexpr23 size_t count_code_points(const char16_t *p, size_t len) { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - char16_t word = scalar::utf16::swap_if_needed(p[i]); - counter += ((word & 0xFC00) != 0xDC00); - } - return counter; +template simdutf_constexpr23 auto count_code_points(const char16_t* p, size_t len) -> size_t { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + char16_t word = scalar::utf16::swap_if_needed(p[i]); + counter += ((word & 0xFC00) != 0xDC00); + } + return counter; } template -simdutf_constexpr23 size_t utf8_length_from_utf16(const char16_t *p, - size_t len) { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - char16_t word = scalar::utf16::swap_if_needed(p[i]); - counter++; // ASCII - counter += static_cast( - word > - 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes - counter += static_cast((word > 0x7FF && word <= 0xD7FF) || - (word >= 0xE000)); // three-byte - } - return counter; +simdutf_constexpr23 auto utf8_length_from_utf16(const char16_t* p, size_t len) -> size_t { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + char16_t word = scalar::utf16::swap_if_needed(p[i]); + counter++; // ASCII + counter += static_cast(word > 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes + counter += static_cast((word > 0x7FF && word <= 0xD7FF) || (word >= 0xE000)); // three-byte + } + return counter; } template -simdutf_constexpr23 size_t utf32_length_from_utf16(const char16_t *p, - size_t len) { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - char16_t word = scalar::utf16::swap_if_needed(p[i]); - counter += ((word & 0xFC00) != 0xDC00); - } - return counter; +simdutf_constexpr23 auto utf32_length_from_utf16(const char16_t* p, size_t len) -> size_t { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + char16_t word = scalar::utf16::swap_if_needed(p[i]); + counter += ((word & 0xFC00) != 0xDC00); + } + return counter; } simdutf_really_inline simdutf_constexpr23 void change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) { for (size_t i = 0; i < size; i++) { - *output++ = char16_t(input[i] >> 8 | input[i] << 8); + *output++ = static_cast(input[i] >> 8 | input[i] << 8); } } template -simdutf_warn_unused simdutf_constexpr23 size_t -trim_partial_utf16(const char16_t *input, size_t length) { - if (length == 0) { - return 0; - } - uint16_t last_word = uint16_t(input[length - 1]); - last_word = scalar::utf16::swap_if_needed(last_word); - length -= ((last_word & 0xFC00) == 0xD800); - return length; +simdutf_warn_unused simdutf_constexpr23 auto trim_partial_utf16(const char16_t* input, size_t length) -> size_t { + if (length == 0) { + return 0; + } + auto lastWord = static_cast(input[length - 1]); + lastWord = scalar::utf16::swap_if_needed(lastWord); + length -= ((lastWord & 0xFC00) == 0xD800); + return length; } -template constexpr bool is_high_surrogate(char16_t c) { - c = scalar::utf16::swap_if_needed(c); - return (0xd800 <= c && c <= 0xdbff); +template constexpr auto is_high_surrogate(char16_t c) -> bool { + c = scalar::utf16::swap_if_needed(c); + return (0xd800 <= c && c <= 0xdbff); } -template constexpr bool is_low_surrogate(char16_t c) { - c = scalar::utf16::swap_if_needed(c); - return (0xdc00 <= c && c <= 0xdfff); +template constexpr auto is_low_surrogate(char16_t c) -> bool { + c = scalar::utf16::swap_if_needed(c); + return (0xdc00 <= c && c <= 0xdfff); } -simdutf_really_inline constexpr bool high_surrogate(char16_t c) { - return (0xd800 <= c && c <= 0xdbff); +simdutf_really_inline constexpr auto high_surrogate(char16_t c) -> bool { + return (0xd800 <= c && c <= 0xdbff); } -simdutf_really_inline constexpr bool low_surrogate(char16_t c) { - return (0xdc00 <= c && c <= 0xdfff); +simdutf_really_inline constexpr auto low_surrogate(char16_t c) -> bool { + return (0xdc00 <= c && c <= 0xdfff); } template -simdutf_constexpr23 result -utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) { - bool any_surrogates = false; - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - if (is_high_surrogate(p[i])) { - any_surrogates = true; - // surrogate pair - if (i + 1 < len && is_low_surrogate(p[i + 1])) { - counter += 4; - i++; // skip low surrogate - } else { - counter += 3; // unpaired high surrogate replaced by U+FFFD - } - continue; - } else if (is_low_surrogate(p[i])) { - any_surrogates = true; - counter += 3; // unpaired low surrogate replaced by U+FFFD - continue; +simdutf_constexpr23 auto utf8_length_from_utf16_with_replacement(const char16_t* p, size_t len) -> result { + bool any_surrogates = false; + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + if (is_high_surrogate(p[i])) { + any_surrogates = true; + // surrogate pair + if (i + 1 < len && is_low_surrogate(p[i + 1])) { + counter += 4; + i++; // skip low surrogate + } else { + counter += 3; // unpaired high surrogate replaced by U+FFFD + } + continue; + } + if (is_low_surrogate(p[i])) { + any_surrogates = true; + counter += 3; // unpaired low surrogate replaced by U+FFFD + continue; + } + char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; + counter++; // at least 1 byte + counter += static_cast(word > 0x7F); // non-ASCII is at least 2 bytes + counter += static_cast(word > 0x7FF); // three-byte } - char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; - counter++; // at least 1 byte - counter += - static_cast(word > 0x7F); // non-ASCII is at least 2 bytes - counter += static_cast(word > 0x7FF); // three-byte - } - return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, - counter}; + return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, counter}; } // variable templates are a C++14 extension -template constexpr char16_t replacement() { - return !match_system(big_endian) ? scalar::u16_swap_bytes(0xfffd) : 0xfffd; +template constexpr auto replacement() -> char16_t { + return !match_system(big_endian) ? scalar::u16_swap_bytes(0xfffd) : 0xfffd; } template simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, char16_t *output) { const char16_t replacement = utf16::replacement(); - bool high_surrogate_prev = false, high_surrogate, low_surrogate; + bool high_surrogate_prev = false; + bool high_surrogate; + bool low_surrogate; size_t i = 0; for (; i < len; i++) { char16_t c = input[i]; @@ -2312,9 +2246,7 @@ simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, } } -} // namespace utf16 -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar::utf16 #endif /* end file include/simdutf/scalar/utf16.h */ @@ -2324,52 +2256,47 @@ simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, #include // for std::memcpy -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf16_to_latin1 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf16 && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf16 && simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - OutputPtr latin_output) { +simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr latinOutput) -> size_t { if (len == 0) { return 0; } size_t pos = 0; - const auto latin_output_start = latin_output; + const auto latinOutputStart = latinOutput; uint16_t word = 0; - uint16_t too_large = 0; + uint16_t tooLarge = 0; while (pos < len) { word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - too_large |= word; - *latin_output++ = char(word & 0xFF); + tooLarge |= word; + *latinOutput++ = static_cast(word & 0xFF); pos++; } - if ((too_large & 0xFF00) != 0) { - return 0; + if ((tooLarge & 0xFF00) != 0) { + return 0; } - return latin_output - latin_output_start; + return latinOutput - latinOutputStart; } template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf16 && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf16 && simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, - OutputPtr latin_output) { +simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPtr latinOutput) -> result { if (len == 0) { - return result(error_code::SUCCESS, 0); + return {error_code::SUCCESS, 0}; } size_t pos = 0; - auto start = latin_output; - uint16_t word; + auto start = latinOutput; + uint16_t word = 0; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -2378,15 +2305,18 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, { if (pos + 16 <= len) { // if it is safe to read 32 more bytes, check that // they are Latin1 - uint64_t v1, v2, v3, v4; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - ::memcpy(&v2, data + pos + 4, sizeof(uint64_t)); - ::memcpy(&v3, data + pos + 8, sizeof(uint64_t)); - ::memcpy(&v4, data + pos + 12, sizeof(uint64_t)); - - if constexpr (!match_system(big_endian)) { - v1 = (v1 >> 8) | (v1 << (64 - 8)); - } + uint64_t v1; + uint64_t v2; + uint64_t v3; + uint64_t v4; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + ::memcpy(&v2, data + pos + 4, sizeof(uint64_t)); + ::memcpy(&v3, data + pos + 8, sizeof(uint64_t)); + ::memcpy(&v4, data + pos + 12, sizeof(uint64_t)); + + if constexpr (!match_system(big_endian)) { + v1 = (v1 >> 8) | (v1 << (64 - 8)); + } if constexpr (!match_system(big_endian)) { v2 = (v2 >> 8) | (v2 << (64 - 8)); } @@ -2398,13 +2328,11 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, } if (((v1 | v2 | v3 | v4) & 0xFF00FF00FF00FF00) == 0) { - size_t final_pos = pos + 16; - while (pos < final_pos) { - *latin_output++ = !match_system(big_endian) - ? char(u16_swap_bytes(data[pos])) - : char(data[pos]); - pos++; - } + size_t finalPos = pos + 16; + while (pos < finalPos) { + *latinOutput++ = !match_system(big_endian) ? char(u16_swap_bytes(data[pos])) : char(data[pos]); + pos++; + } continue; } } @@ -2412,19 +2340,18 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF00) == 0) { - *latin_output++ = char(word & 0xFF); - pos++; + *latinOutput++ = static_cast(word & 0xFF); + pos++; } else { - return result(error_code::TOO_LARGE, pos); + return {error_code::TOO_LARGE, pos}; } } - return result(error_code::SUCCESS, latin_output - start); + return result(error_code::SUCCESS, latinOutput - start); } } // namespace utf16_to_latin1 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf16_to_latin1/utf16_to_latin1.h */ @@ -2432,41 +2359,34 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, #ifndef SIMDUTF_VALID_UTF16_TO_LATIN1_H #define SIMDUTF_VALID_UTF16_TO_LATIN1_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf16_to_latin1 { template -simdutf_constexpr23 inline size_t -convert_valid_impl(InputIterator data, size_t len, - OutputIterator latin_output) { - static_assert( - std::is_same::type, uint16_t>::value, - "must decay to uint16_t"); - size_t pos = 0; - const auto start = latin_output; - uint16_t word = 0; - - while (pos < len) { - word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - *latin_output++ = char(word); - pos++; - } +simdutf_constexpr23 inline auto convert_valid_impl(InputIterator data, size_t len, OutputIterator latinOutput) + -> size_t { + static_assert(std::is_same_v, uint16_t>, "must decay to uint16_t"); + size_t pos = 0; + const auto start = latinOutput; + uint16_t word = 0; + + while (pos < len) { + word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; + *latinOutput++ = static_cast(word); + pos++; + } - return latin_output - start; + return latinOutput - start; } template -simdutf_really_inline size_t convert_valid(const char16_t *buf, size_t len, - char *latin_output) { - return convert_valid_impl(reinterpret_cast(buf), - len, latin_output); +simdutf_really_inline auto convert_valid(const char16_t* buf, size_t len, char* latinOutput) -> size_t { + return convert_valid_impl(reinterpret_cast(buf), len, latinOutput); } } // namespace utf16_to_latin1 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf16_to_latin1/valid_utf16_to_latin1.h */ @@ -2474,87 +2394,77 @@ simdutf_really_inline size_t convert_valid(const char16_t *buf, size_t len, #ifndef SIMDUTF_UTF16_TO_UTF32_H #define SIMDUTF_UTF16_TO_UTF32_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf16_to_utf32 { template -simdutf_constexpr23 size_t convert(const char16_t *data, size_t len, - char32_t *utf32_output) { - size_t pos = 0; - char32_t *start{utf32_output}; - while (pos < len) { - uint16_t word = - !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - if ((word & 0xF800) != 0xD800) { - // No surrogate pair, extend 16-bit word to 32-bit word - *utf32_output++ = char32_t(word); - pos++; - } else { - // must be a surrogate pair - uint16_t diff = uint16_t(word - 0xD800); - if (diff > 0x3FF) { - return 0; - } - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - uint16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - uint16_t diff2 = uint16_t(next_word - 0xDC00); - if (diff2 > 0x3FF) { - return 0; - } - uint32_t value = (diff << 10) + diff2 + 0x10000; - *utf32_output++ = char32_t(value); - pos += 2; +simdutf_constexpr23 auto convert(const char16_t* data, size_t len, char32_t* utf32Output) -> size_t { + size_t pos = 0; + char32_t* start{utf32Output}; + while (pos < len) { + uint16_t word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; + if ((word & 0xF800) != 0xD800) { + // No surrogate pair, extend 16-bit word to 32-bit word + *utf32Output++ = static_cast(word); + pos++; + } else { + // must be a surrogate pair + auto diff = static_cast(word - 0xD800); + if (diff > 0x3FF) { + return 0; + } + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + auto diff2 = static_cast(nextWord - 0xDC00); + if (diff2 > 0x3FF) { + return 0; + } + uint32_t value = (diff << 10) + diff2 + 0x10000; + *utf32Output++ = static_cast(value); + pos += 2; + } } - } - return utf32_output - start; + return utf32Output - start; } template -simdutf_constexpr23 result convert_with_errors(const char16_t *data, size_t len, - char32_t *utf32_output) { - size_t pos = 0; - char32_t *start{utf32_output}; - while (pos < len) { - uint16_t word = - !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - if ((word & 0xF800) != 0xD800) { - // No surrogate pair, extend 16-bit word to 32-bit word - *utf32_output++ = char32_t(word); - pos++; - } else { - // must be a surrogate pair - uint16_t diff = uint16_t(word - 0xD800); - if (diff > 0x3FF) { - return result(error_code::SURROGATE, pos); - } - if (pos + 1 >= len) { - return result(error_code::SURROGATE, pos); - } // minimal bound checking - uint16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - uint16_t diff2 = uint16_t(next_word - 0xDC00); - if (diff2 > 0x3FF) { - return result(error_code::SURROGATE, pos); - } - uint32_t value = (diff << 10) + diff2 + 0x10000; - *utf32_output++ = char32_t(value); - pos += 2; +simdutf_constexpr23 auto convert_with_errors(const char16_t* data, size_t len, char32_t* utf32Output) -> result { + size_t pos = 0; + char32_t* start{utf32Output}; + while (pos < len) { + uint16_t word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; + if ((word & 0xF800) != 0xD800) { + // No surrogate pair, extend 16-bit word to 32-bit word + *utf32Output++ = static_cast(word); + pos++; + } else { + // must be a surrogate pair + auto diff = static_cast(word - 0xD800); + if (diff > 0x3FF) { + return {error_code::SURROGATE, pos}; + } + if (pos + 1 >= len) { + return {error_code::SURROGATE, pos}; + } // minimal bound checking + uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + auto diff2 = static_cast(nextWord - 0xDC00); + if (diff2 > 0x3FF) { + return {error_code::SURROGATE, pos}; + } + uint32_t value = (diff << 10) + diff2 + 0x10000; + *utf32Output++ = static_cast(value); + pos += 2; + } } - } - return result(error_code::SUCCESS, utf32_output - start); + return {error_code::SUCCESS, utf32Output - start}; } } // namespace utf16_to_utf32 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf16_to_utf32/utf16_to_utf32.h */ @@ -2562,45 +2472,39 @@ simdutf_constexpr23 result convert_with_errors(const char16_t *data, size_t len, #ifndef SIMDUTF_VALID_UTF16_TO_UTF32_H #define SIMDUTF_VALID_UTF16_TO_UTF32_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf16_to_utf32 { template -simdutf_constexpr23 size_t convert_valid(const char16_t *data, size_t len, - char32_t *utf32_output) { - size_t pos = 0; - char32_t *start{utf32_output}; - while (pos < len) { - uint16_t word = - !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - if ((word & 0xF800) != 0xD800) { - // No surrogate pair, extend 16-bit word to 32-bit word - *utf32_output++ = char32_t(word); - pos++; - } else { - // must be a surrogate pair - uint16_t diff = uint16_t(word - 0xD800); - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - uint16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - uint16_t diff2 = uint16_t(next_word - 0xDC00); - uint32_t value = (diff << 10) + diff2 + 0x10000; - *utf32_output++ = char32_t(value); - pos += 2; +simdutf_constexpr23 auto convert_valid(const char16_t* data, size_t len, char32_t* utf32Output) -> size_t { + size_t pos = 0; + char32_t* start{utf32Output}; + while (pos < len) { + uint16_t word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; + if ((word & 0xF800) != 0xD800) { + // No surrogate pair, extend 16-bit word to 32-bit word + *utf32Output++ = static_cast(word); + pos++; + } else { + // must be a surrogate pair + auto diff = static_cast(word - 0xD800); + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + auto diff2 = static_cast(nextWord - 0xDC00); + uint32_t value = (diff << 10) + diff2 + 0x10000; + *utf32Output++ = static_cast(value); + pos += 2; + } } - } - return utf32_output - start; + return utf32Output - start; } } // namespace utf16_to_utf32 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf16_to_utf32/valid_utf16_to_utf32.h */ @@ -2608,20 +2512,18 @@ simdutf_constexpr23 size_t convert_valid(const char16_t *data, size_t len, #ifndef SIMDUTF_UTF16_TO_UTF8_H #define SIMDUTF_UTF16_TO_UTF8_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf16_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_utf16 + requires simdutf::detail::indexes_into_utf16 // FIXME constrain output as well #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - OutputPtr utf8_output) { +simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { size_t pos = 0; - const auto start = utf8_output; + const auto start = utf8Output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -2630,19 +2532,17 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, // try to convert the next block of 8 bytes if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if constexpr (!match_system(big_endian)) { - v = (v >> 8) | (v << (64 - 8)); - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if constexpr (!match_system(big_endian)) { + v = (v >> 8) | (v << (64 - 8)); + } if ((v & 0xFF80FF80FF80FF80) == 0) { - size_t final_pos = pos + 4; - while (pos < final_pos) { - *utf8_output++ = !match_system(big_endian) - ? char(u16_swap_bytes(data[pos])) - : char(data[pos]); - pos++; - } + size_t finalPos = pos + 4; + while (pos < finalPos) { + *utf8Output++ = !match_system(big_endian) ? char(u16_swap_bytes(data[pos])) : char(data[pos]); + pos++; + } continue; } } @@ -2651,66 +2551,61 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF80) == 0) { // will generate one UTF-8 bytes - *utf8_output++ = char(word); + *utf8Output++ = static_cast(word); pos++; } else if ((word & 0xF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 6) | 0b11000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 6) | 0b11000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xF800) != 0xD800) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 12) | 0b11100000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 12) | 0b11100000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else { // must be a surrogate pair if (pos + 1 >= len) { return 0; } - uint16_t diff = uint16_t(word - 0xD800); + auto diff = static_cast(word - 0xD800); if (diff > 0x3FF) { return 0; } - uint16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - uint16_t diff2 = uint16_t(next_word - 0xDC00); + uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + auto diff2 = static_cast(nextWord - 0xDC00); if (diff2 > 0x3FF) { return 0; } uint32_t value = (diff << 10) + diff2 + 0x10000; // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - *utf8_output++ = char((value >> 18) | 0b11110000); - *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); - *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((value & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((value >> 18) | 0b11110000); + *utf8Output++ = static_cast(((value >> 12) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast(((value >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((value & 0b111111) | 0b10000000); pos += 2; } } - return utf8_output - start; + return utf8Output - start; } -template +template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf16 && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf16 && simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 full_result convert_with_errors(InputPtr data, size_t len, - OutputPtr utf8_output, - size_t utf8_len = 0) { - if (check_output && utf8_len == 0) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, 0, 0); - } +simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPtr utf8Output, size_t utf8Len = 0) + -> full_result { + if (check_output && utf8Len == 0) { + return {error_code::OUTPUT_BUFFER_TOO_SMALL, 0, 0}; + } size_t pos = 0; - auto start = utf8_output; - auto end = utf8_output + utf8_len; + auto start = utf8Output; + auto end = utf8Output + utf8Len; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -2720,22 +2615,20 @@ simdutf_constexpr23 full_result convert_with_errors(InputPtr data, size_t len, // try to convert the next block of 8 bytes if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if constexpr (!match_system(big_endian)) - v = (v >> 8) | (v << (64 - 8)); + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if constexpr (!match_system(big_endian)) { + v = (v >> 8) | (v << (64 - 8)); + } if ((v & 0xFF80FF80FF80FF80) == 0) { - size_t final_pos = pos + 4; - while (pos < final_pos) { - if (check_output && size_t(end - utf8_output) < 1) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, - utf8_output - start); + size_t finalPos = pos + 4; + while (pos < finalPos) { + if (check_output && size_t(end - utf8Output) < 1) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); + } + *utf8Output++ = !match_system(big_endian) ? char(u16_swap_bytes(data[pos])) : char(data[pos]); + pos++; } - *utf8_output++ = !match_system(big_endian) - ? char(u16_swap_bytes(data[pos])) - : char(data[pos]); - pos++; - } continue; } } @@ -2745,81 +2638,71 @@ simdutf_constexpr23 full_result convert_with_errors(InputPtr data, size_t len, !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF80) == 0) { // will generate one UTF-8 bytes - if (check_output && size_t(end - utf8_output) < 1) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, - utf8_output - start); + if (check_output && size_t(end - utf8Output) < 1) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); } - *utf8_output++ = char(word); + *utf8Output++ = static_cast(word); pos++; } else if ((word & 0xF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - if (check_output && size_t(end - utf8_output) < 2) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, - utf8_output - start); + if (check_output && size_t(end - utf8Output) < 2) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); } - *utf8_output++ = char((word >> 6) | 0b11000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 6) | 0b11000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xF800) != 0xD800) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - if (check_output && size_t(end - utf8_output) < 3) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, - utf8_output - start); + if (check_output && size_t(end - utf8Output) < 3) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); } - *utf8_output++ = char((word >> 12) | 0b11100000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 12) | 0b11100000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else { - - if (check_output && size_t(end - utf8_output) < 4) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, - utf8_output - start); - } + if (check_output && size_t(end - utf8Output) < 4) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); + } // must be a surrogate pair if (pos + 1 >= len) { - return full_result(error_code::SURROGATE, pos, utf8_output - start); + return full_result(error_code::SURROGATE, pos, utf8Output - start); } - uint16_t diff = uint16_t(word - 0xD800); + auto diff = static_cast(word - 0xD800); if (diff > 0x3FF) { - return full_result(error_code::SURROGATE, pos, utf8_output - start); + return full_result(error_code::SURROGATE, pos, utf8Output - start); } - uint16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - uint16_t diff2 = uint16_t(next_word - 0xDC00); + uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + auto diff2 = static_cast(nextWord - 0xDC00); if (diff2 > 0x3FF) { - return full_result(error_code::SURROGATE, pos, utf8_output - start); + return full_result(error_code::SURROGATE, pos, utf8Output - start); } uint32_t value = (diff << 10) + diff2 + 0x10000; // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - *utf8_output++ = char((value >> 18) | 0b11110000); - *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); - *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((value & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((value >> 18) | 0b11110000); + *utf8Output++ = static_cast(((value >> 12) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast(((value >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((value & 0b111111) | 0b10000000); pos += 2; } } - return full_result(error_code::SUCCESS, pos, utf8_output - start); + return full_result(error_code::SUCCESS, pos, utf8Output - start); } template -inline result simple_convert_with_errors(const char16_t *buf, size_t len, - char *utf8_output) { - return convert_with_errors(buf, len, utf8_output, 0); +inline auto simple_convert_with_errors(const char16_t* buf, size_t len, char* utf8Output) -> result { + return convert_with_errors(buf, len, utf8Output, 0); } template -simdutf_constexpr23 size_t convert_with_replacement(const char16_t *data, - size_t len, - char *utf8_output) { - size_t pos = 0; - char *start = utf8_output; - while (pos < len) { +simdutf_constexpr23 auto convert_with_replacement(const char16_t* data, size_t len, char* utf8Output) -> size_t { + size_t pos = 0; + char* start = utf8Output; + while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval #endif @@ -2827,19 +2710,18 @@ simdutf_constexpr23 size_t convert_with_replacement(const char16_t *data, // try to convert the next block of 8 bytes if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if constexpr (!match_system(big_endian)) { - v = (v >> 8) | (v << (64 - 8)); - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if constexpr (!match_system(big_endian)) { + v = (v >> 8) | (v << (64 - 8)); + } if ((v & 0xFF80FF80FF80FF80) == 0) { - size_t final_pos = pos + 4; - while (pos < final_pos) { - *utf8_output++ = !match_system(big_endian) - ? char(u16_swap_bytes(data[pos])) - : char(data[pos]); - pos++; - } + size_t finalPos = pos + 4; + while (pos < finalPos) { + *utf8Output++ = !match_system(big_endian) ? static_cast(u16_swap_bytes(data[pos])) + : static_cast(data[pos]); + pos++; + } continue; } } @@ -2848,56 +2730,53 @@ simdutf_constexpr23 size_t convert_with_replacement(const char16_t *data, !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF80) == 0) { // will generate one UTF-8 bytes - *utf8_output++ = char(word); + *utf8Output++ = static_cast(word); pos++; } else if ((word & 0xF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 6) | 0b11000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 6) | 0b11000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xF800) != 0xD800) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 12) | 0b11100000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 12) | 0b11100000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else { // surrogate range - uint16_t diff = uint16_t(word - 0xD800); + auto diff = static_cast(word - 0xD800); if (diff <= 0x3FF && pos + 1 < len) { // high surrogate, check for valid pair - uint16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - uint16_t diff2 = uint16_t(next_word - 0xDC00); + uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + auto diff2 = static_cast(nextWord - 0xDC00); if (diff2 <= 0x3FF) { // valid surrogate pair uint32_t value = (diff << 10) + diff2 + 0x10000; // will generate four UTF-8 bytes - *utf8_output++ = char((value >> 18) | 0b11110000); - *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); - *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((value & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((value >> 18) | 0b11110000); + *utf8Output++ = static_cast(((value >> 12) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast(((value >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((value & 0b111111) | 0b10000000); pos += 2; continue; } } // unpaired surrogate: replace with U+FFFD (0xEF 0xBF 0xBD) - *utf8_output++ = char(0xef); - *utf8_output++ = char(0xbf); - *utf8_output++ = char(0xbd); + *utf8Output++ = static_cast(0xef); + *utf8Output++ = static_cast(0xbf); + *utf8Output++ = static_cast(0xbd); pos++; } } - return utf8_output - start; + return utf8Output - start; } } // namespace utf16_to_utf8 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf16_to_utf8/utf16_to_utf8.h */ @@ -2905,20 +2784,17 @@ simdutf_constexpr23 size_t convert_with_replacement(const char16_t *data, #ifndef SIMDUTF_VALID_UTF16_TO_UTF8_H #define SIMDUTF_VALID_UTF16_TO_UTF8_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf16_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf16 && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf16 && simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, - OutputPtr utf8_output) { +simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { size_t pos = 0; - auto start = utf8_output; + auto start = utf8Output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -2927,19 +2803,17 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, // try to convert the next block of 4 ASCII characters if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if constexpr (!match_system(big_endian)) { - v = (v >> 8) | (v << (64 - 8)); - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if constexpr (!match_system(big_endian)) { + v = (v >> 8) | (v << (64 - 8)); + } if ((v & 0xFF80FF80FF80FF80) == 0) { - size_t final_pos = pos + 4; - while (pos < final_pos) { - *utf8_output++ = !match_system(big_endian) - ? char(u16_swap_bytes(data[pos])) - : char(data[pos]); - pos++; - } + size_t finalPos = pos + 4; + while (pos < finalPos) { + *utf8Output++ = !match_system(big_endian) ? char(u16_swap_bytes(data[pos])) : char(data[pos]); + pos++; + } continue; } } @@ -2949,48 +2823,45 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF80) == 0) { // will generate one UTF-8 bytes - *utf8_output++ = char(word); + *utf8Output++ = static_cast(word); pos++; } else if ((word & 0xF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 6) | 0b11000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 6) | 0b11000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xF800) != 0xD800) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 12) | 0b11100000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 12) | 0b11100000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else { // must be a surrogate pair - uint16_t diff = uint16_t(word - 0xD800); + auto diff = static_cast(word - 0xD800); if (pos + 1 >= len) { return 0; } // minimal bound checking - uint16_t next_word = !match_system(big_endian) - ? u16_swap_bytes(data[pos + 1]) - : data[pos + 1]; - uint16_t diff2 = uint16_t(next_word - 0xDC00); + uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; + auto diff2 = static_cast(nextWord - 0xDC00); uint32_t value = (diff << 10) + diff2 + 0x10000; // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - *utf8_output++ = char((value >> 18) | 0b11110000); - *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); - *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((value & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((value >> 18) | 0b11110000); + *utf8Output++ = static_cast(((value >> 12) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast(((value >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((value & 0b111111) | 0b10000000); pos += 2; } } - return utf8_output - start; + return utf8Output - start; } } // namespace utf16_to_utf8 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf16_to_utf8/valid_utf16_to_utf8.h */ @@ -2998,16 +2869,13 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, #ifndef SIMDUTF_UTF32_H #define SIMDUTF_UTF32_H -namespace simdutf { -namespace scalar { -namespace utf32 { +namespace simdutf::scalar::utf32 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_uint32 + requires simdutf::detail::indexes_into_uint32 #endif -simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, - size_t len) noexcept { +simdutf_warn_unused simdutf_constexpr23 auto validate(InputPtr data, size_t len) noexcept -> bool { uint64_t pos = 0; for (; pos < len; pos++) { uint32_t word = data[pos]; @@ -3018,63 +2886,57 @@ simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, return true; } -simdutf_warn_unused simdutf_really_inline bool validate(const char32_t *buf, - size_t len) noexcept { - return validate(reinterpret_cast(buf), len); +simdutf_warn_unused simdutf_really_inline auto validate(const char32_t* buf, size_t len) noexcept -> bool { + return validate(reinterpret_cast(buf), len); } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_uint32 + requires simdutf::detail::indexes_into_uint32 #endif -simdutf_warn_unused simdutf_constexpr23 result -validate_with_errors(InputPtr data, size_t len) noexcept { +simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(InputPtr data, size_t len) noexcept -> result { size_t pos = 0; for (; pos < len; pos++) { uint32_t word = data[pos]; if (word > 0x10FFFF) { - return result(error_code::TOO_LARGE, pos); + return {error_code::TOO_LARGE, pos}; } if (word >= 0xD800 && word <= 0xDFFF) { - return result(error_code::SURROGATE, pos); + return {error_code::SURROGATE, pos}; } } - return result(error_code::SUCCESS, pos); + return {error_code::SUCCESS, pos}; } -simdutf_warn_unused simdutf_really_inline result -validate_with_errors(const char32_t *buf, size_t len) noexcept { - return validate_with_errors(reinterpret_cast(buf), len); +simdutf_warn_unused simdutf_really_inline auto validate_with_errors(const char32_t* buf, size_t len) noexcept + -> result { + return validate_with_errors(reinterpret_cast(buf), len); } -inline simdutf_constexpr23 size_t utf8_length_from_utf32(const char32_t *p, - size_t len) { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - // credit: @ttsugriy for the vectorizable approach - counter++; // ASCII - counter += static_cast(p[i] > 0x7F); // two-byte - counter += static_cast(p[i] > 0x7FF); // three-byte - counter += static_cast(p[i] > 0xFFFF); // four-bytes - } - return counter; +simdutf_constexpr23 auto utf8_length_from_utf32(const char32_t* p, size_t len) -> size_t { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + // credit: @ttsugriy for the vectorizable approach + counter++; // ASCII + counter += static_cast(p[i] > 0x7F); // two-byte + counter += static_cast(p[i] > 0x7FF); // three-byte + counter += static_cast(p[i] > 0xFFFF); // four-bytes + } + return counter; } -inline simdutf_warn_unused simdutf_constexpr23 size_t -utf16_length_from_utf32(const char32_t *p, size_t len) { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - counter++; // non-surrogate word - counter += static_cast(p[i] > 0xFFFF); // surrogate pair - } - return counter; +simdutf_warn_unused simdutf_constexpr23 auto utf16_length_from_utf32(const char32_t* p, size_t len) -> size_t { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + counter++; // non-surrogate word + counter += static_cast(p[i] > 0xFFFF); // surrogate pair + } + return counter; } -} // namespace utf32 -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar::utf32 #endif /* end file include/simdutf/scalar/utf32.h */ @@ -3082,69 +2944,63 @@ utf16_length_from_utf32(const char32_t *p, size_t len) { #ifndef SIMDUTF_UTF32_TO_LATIN1_H #define SIMDUTF_UTF32_TO_LATIN1_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf32_to_latin1 { -inline simdutf_constexpr23 size_t convert(const char32_t *data, size_t len, - char *latin1_output) { - char *start = latin1_output; - uint32_t utf32_char; - size_t pos = 0; - uint32_t too_large = 0; +simdutf_constexpr23 auto convert(const char32_t* data, size_t len, char* latin1Output) -> size_t { + char* start = latin1Output; + uint32_t utf32Char = 0; + size_t pos = 0; + uint32_t tooLarge = 0; - while (pos < len) { - utf32_char = (uint32_t)data[pos]; - too_large |= utf32_char; - *latin1_output++ = (char)(utf32_char & 0xFF); - pos++; - } - if ((too_large & 0xFFFFFF00) != 0) { - return 0; - } - return latin1_output - start; + while (pos < len) { + utf32Char = static_cast(data[pos]); + tooLarge |= utf32Char; + *latin1Output++ = static_cast(utf32Char & 0xFF); + pos++; + } + if ((tooLarge & 0xFFFFFF00) != 0) { + return 0; + } + return latin1Output - start; } -inline simdutf_constexpr23 result convert_with_errors(const char32_t *data, - size_t len, - char *latin1_output) { - char *start{latin1_output}; - size_t pos = 0; - while (pos < len) { +simdutf_constexpr23 auto convert_with_errors(const char32_t* data, size_t len, char* latin1Output) -> result { + char* start{latin1Output}; + size_t pos = 0; + while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval #endif { if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that // they are Latin1 - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0xFFFFFF00FFFFFF00) == 0) { - *latin1_output++ = char(data[pos]); - *latin1_output++ = char(data[pos + 1]); - pos += 2; - continue; - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF00FFFFFF00) == 0) { + *latin1Output++ = static_cast(data[pos]); + *latin1Output++ = static_cast(data[pos + 1]); + pos += 2; + continue; + } } } - uint32_t utf32_char = data[pos]; - if ((utf32_char & 0xFFFFFF00) == - 0) { // Check if the character can be represented in Latin-1 - *latin1_output++ = (char)(utf32_char & 0xFF); - pos++; + uint32_t utf32Char = data[pos]; + if ((utf32Char & 0xFFFFFF00) == 0) { // Check if the character can be represented in Latin-1 + *latin1Output++ = static_cast(utf32Char & 0xFF); + pos++; } else { - return result(error_code::TOO_LARGE, pos); + return {error_code::TOO_LARGE, pos}; }; } - return result(error_code::SUCCESS, latin1_output - start); + return {error_code::SUCCESS, latin1Output - start}; } } // namespace utf32_to_latin1 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf32_to_latin1/utf32_to_latin1.h */ @@ -3152,23 +3008,20 @@ inline simdutf_constexpr23 result convert_with_errors(const char32_t *data, #ifndef SIMDUTF_VALID_UTF32_TO_LATIN1_H #define SIMDUTF_VALID_UTF32_TO_LATIN1_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf32_to_latin1 { template -simdutf_constexpr23 size_t convert_valid(ReadPtr data, size_t len, - WritePtr latin1_output) { - static_assert( - std::is_same::type, uint32_t>::value, - "dereferencing the data pointer must result in a uint32_t"); - auto start = latin1_output; - uint32_t utf32_char; - size_t pos = 0; +simdutf_constexpr23 auto convert_valid(ReadPtr data, size_t len, WritePtr latin1Output) -> size_t { + static_assert(std::is_same_v, uint32_t>, + "dereferencing the data pointer must result in a uint32_t"); + auto start = latin1Output; + uint32_t utf32Char = 0; + size_t pos = 0; - while (pos < len) { - utf32_char = data[pos]; + while (pos < len) { + utf32Char = data[pos]; #if SIMDUTF_CPLUSPLUS23 // avoid using the 8 byte at a time optimization in constant evaluation @@ -3178,42 +3031,38 @@ simdutf_constexpr23 size_t convert_valid(ReadPtr data, size_t len, #endif if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that they are Latin1 - uint64_t v; + uint64_t v = 0; std::memcpy(&v, data + pos, sizeof(uint64_t)); if ((v & 0xFFFFFF00FFFFFF00) == 0) { - *latin1_output++ = char(data[pos]); - *latin1_output++ = char(data[pos + 1]); - pos += 2; - continue; - } else { - // output can not be represented in latin1 - return 0; + *latin1Output++ = char(data[pos]); + *latin1Output++ = char(data[pos + 1]); + pos += 2; + continue; } + // output can not be represented in latin1 + return 0; } #if SIMDUTF_CPLUSPLUS23 } // if ! consteval #endif - if ((utf32_char & 0xFFFFFF00) == 0) { - *latin1_output++ = char(utf32_char); + if ((utf32Char & 0xFFFFFF00) == 0) { + *latin1Output++ = static_cast(utf32Char); } else { - // output can not be represented in latin1 - return 0; + // output can not be represented in latin1 + return 0; } pos++; } - return latin1_output - start; + return latin1Output - start; } -simdutf_really_inline size_t convert_valid(const char32_t *buf, size_t len, - char *latin1_output) { - return convert_valid(reinterpret_cast(buf), len, - latin1_output); +simdutf_really_inline auto convert_valid(const char32_t* buf, size_t len, char* latin1Output) -> size_t { + return convert_valid(reinterpret_cast(buf), len, latin1Output); } } // namespace utf32_to_latin1 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf32_to_latin1/valid_utf32_to_latin1.h */ @@ -3221,85 +3070,81 @@ simdutf_really_inline size_t convert_valid(const char32_t *buf, size_t len, #ifndef SIMDUTF_UTF32_TO_UTF16_H #define SIMDUTF_UTF32_TO_UTF16_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf32_to_utf16 { template -simdutf_constexpr23 size_t convert(const char32_t *data, size_t len, - char16_t *utf16_output) { - size_t pos = 0; - char16_t *start{utf16_output}; - while (pos < len) { - uint32_t word = data[pos]; - if ((word & 0xFFFF0000) == 0) { - if (word >= 0xD800 && word <= 0xDFFF) { - return 0; - } - // will not generate a surrogate pair - *utf16_output++ = !match_system(big_endian) - ? char16_t(u16_swap_bytes(uint16_t(word))) - : char16_t(word); - } else { - // will generate a surrogate pair - if (word > 0x10FFFF) { - return 0; - } - word -= 0x10000; - uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); - uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); - if constexpr (!match_system(big_endian)) { - high_surrogate = u16_swap_bytes(high_surrogate); - low_surrogate = u16_swap_bytes(low_surrogate); - } - *utf16_output++ = char16_t(high_surrogate); - *utf16_output++ = char16_t(low_surrogate); +simdutf_constexpr23 auto convert(const char32_t* data, size_t len, char16_t* utf16Output) -> size_t { + size_t pos = 0; + char16_t* start{utf16Output}; + while (pos < len) { + uint32_t word = data[pos]; + if ((word & 0xFFFF0000) == 0) { + if (word >= 0xD800 && word <= 0xDFFF) { + return 0; + } + // will not generate a surrogate pair + *utf16Output++ = !match_system(big_endian) + ? static_cast(u16_swap_bytes(static_cast(word))) + : static_cast(word); + } else { + // will generate a surrogate pair + if (word > 0x10FFFF) { + return 0; + } + word -= 0x10000; + auto highSurrogate = static_cast(0xD800 + (word >> 10)); + auto lowSurrogate = static_cast(0xDC00 + (word & 0x3FF)); + if constexpr (!match_system(big_endian)) { + highSurrogate = u16_swap_bytes(highSurrogate); + lowSurrogate = u16_swap_bytes(lowSurrogate); + } + *utf16Output++ = static_cast(highSurrogate); + *utf16Output++ = static_cast(lowSurrogate); + } + pos++; } - pos++; - } - return utf16_output - start; + return utf16Output - start; } template -simdutf_constexpr23 result convert_with_errors(const char32_t *data, size_t len, - char16_t *utf16_output) { - size_t pos = 0; - char16_t *start{utf16_output}; - while (pos < len) { - uint32_t word = data[pos]; - if ((word & 0xFFFF0000) == 0) { - if (word >= 0xD800 && word <= 0xDFFF) { - return result(error_code::SURROGATE, pos); - } - // will not generate a surrogate pair - *utf16_output++ = !match_system(big_endian) - ? char16_t(u16_swap_bytes(uint16_t(word))) - : char16_t(word); - } else { - // will generate a surrogate pair - if (word > 0x10FFFF) { - return result(error_code::TOO_LARGE, pos); - } - word -= 0x10000; - uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); - uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); - if constexpr (!match_system(big_endian)) { - high_surrogate = u16_swap_bytes(high_surrogate); - low_surrogate = u16_swap_bytes(low_surrogate); - } - *utf16_output++ = char16_t(high_surrogate); - *utf16_output++ = char16_t(low_surrogate); +simdutf_constexpr23 auto convert_with_errors(const char32_t* data, size_t len, char16_t* utf16Output) -> result { + size_t pos = 0; + char16_t* start{utf16Output}; + while (pos < len) { + uint32_t word = data[pos]; + if ((word & 0xFFFF0000) == 0) { + if (word >= 0xD800 && word <= 0xDFFF) { + return {error_code::SURROGATE, pos}; + } + // will not generate a surrogate pair + *utf16Output++ = !match_system(big_endian) + ? static_cast(u16_swap_bytes(static_cast(word))) + : static_cast(word); + } else { + // will generate a surrogate pair + if (word > 0x10FFFF) { + return {error_code::TOO_LARGE, pos}; + } + word -= 0x10000; + auto highSurrogate = static_cast(0xD800 + (word >> 10)); + auto lowSurrogate = static_cast(0xDC00 + (word & 0x3FF)); + if constexpr (!match_system(big_endian)) { + highSurrogate = u16_swap_bytes(highSurrogate); + lowSurrogate = u16_swap_bytes(lowSurrogate); + } + *utf16Output++ = static_cast(highSurrogate); + *utf16Output++ = static_cast(lowSurrogate); + } + pos++; } - pos++; - } - return result(error_code::SUCCESS, utf16_output - start); + return {error_code::SUCCESS, utf16Output - start}; } } // namespace utf32_to_utf16 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf32_to_utf16/utf32_to_utf16.h */ @@ -3307,45 +3152,42 @@ simdutf_constexpr23 result convert_with_errors(const char32_t *data, size_t len, #ifndef SIMDUTF_VALID_UTF32_TO_UTF16_H #define SIMDUTF_VALID_UTF32_TO_UTF16_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf32_to_utf16 { template -simdutf_constexpr23 size_t convert_valid(const char32_t *data, size_t len, - char16_t *utf16_output) { - size_t pos = 0; - char16_t *start{utf16_output}; - while (pos < len) { - uint32_t word = data[pos]; - if ((word & 0xFFFF0000) == 0) { - // will not generate a surrogate pair - *utf16_output++ = !match_system(big_endian) - ? char16_t(u16_swap_bytes(uint16_t(word))) - : char16_t(word); - pos++; - } else { - // will generate a surrogate pair - word -= 0x10000; - uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); - uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); - if constexpr (!match_system(big_endian)) { - high_surrogate = u16_swap_bytes(high_surrogate); - low_surrogate = u16_swap_bytes(low_surrogate); - } - *utf16_output++ = char16_t(high_surrogate); - *utf16_output++ = char16_t(low_surrogate); - pos++; +simdutf_constexpr23 auto convert_valid(const char32_t* data, size_t len, char16_t* utf16Output) -> size_t { + size_t pos = 0; + char16_t* start{utf16Output}; + while (pos < len) { + uint32_t word = data[pos]; + if ((word & 0xFFFF0000) == 0) { + // will not generate a surrogate pair + *utf16Output++ = !match_system(big_endian) + ? static_cast(u16_swap_bytes(static_cast(word))) + : static_cast(word); + pos++; + } else { + // will generate a surrogate pair + word -= 0x10000; + auto highSurrogate = static_cast(0xD800 + (word >> 10)); + auto lowSurrogate = static_cast(0xDC00 + (word & 0x3FF)); + if constexpr (!match_system(big_endian)) { + highSurrogate = u16_swap_bytes(highSurrogate); + lowSurrogate = u16_swap_bytes(lowSurrogate); + } + *utf16Output++ = static_cast(highSurrogate); + *utf16Output++ = static_cast(lowSurrogate); + pos++; + } } - } - return utf16_output - start; + return utf16Output - start; } } // namespace utf32_to_utf16 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf32_to_utf16/valid_utf32_to_utf16.h */ @@ -3353,20 +3195,17 @@ simdutf_constexpr23 size_t convert_valid(const char32_t *data, size_t len, #ifndef SIMDUTF_UTF32_TO_UTF8_H #define SIMDUTF_UTF32_TO_UTF8_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf32_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf32 && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf32 && simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - OutputPtr utf8_output) { +simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { size_t pos = 0; - auto start = utf8_output; + auto start = utf8Output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -3374,27 +3213,27 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, { // try to convert the next block of 2 ASCII characters if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0xFFFFFF80FFFFFF80) == 0) { - *utf8_output++ = char(data[pos]); - *utf8_output++ = char(data[pos + 1]); - pos += 2; - continue; - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF80FFFFFF80) == 0) { + *utf8Output++ = char(data[pos]); + *utf8Output++ = char(data[pos + 1]); + pos += 2; + continue; + } } } uint32_t word = data[pos]; if ((word & 0xFFFFFF80) == 0) { // will generate one UTF-8 bytes - *utf8_output++ = char(word); + *utf8Output++ = static_cast(word); pos++; } else if ((word & 0xFFFFF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 6) | 0b11000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 6) | 0b11000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xFFFF0000) == 0) { // will generate three UTF-8 bytes @@ -3402,9 +3241,9 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, if (word >= 0xD800 && word <= 0xDFFF) { return 0; } - *utf8_output++ = char((word >> 12) | 0b11100000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 12) | 0b11100000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else { // will generate four UTF-8 bytes @@ -3412,25 +3251,23 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, if (word > 0x10FFFF) { return 0; } - *utf8_output++ = char((word >> 18) | 0b11110000); - *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 18) | 0b11110000); + *utf8Output++ = static_cast(((word >> 12) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } } - return utf8_output - start; + return utf8Output - start; } template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf32 && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf32 && simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, - OutputPtr utf8_output) { +simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPtr utf8Output) -> result { size_t pos = 0; - auto start = utf8_output; + auto start = utf8Output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -3438,58 +3275,57 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, { // try to convert the next block of 2 ASCII characters if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0xFFFFFF80FFFFFF80) == 0) { - *utf8_output++ = char(data[pos]); - *utf8_output++ = char(data[pos + 1]); - pos += 2; - continue; - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF80FFFFFF80) == 0) { + *utf8Output++ = char(data[pos]); + *utf8Output++ = char(data[pos + 1]); + pos += 2; + continue; + } } } uint32_t word = data[pos]; if ((word & 0xFFFFFF80) == 0) { // will generate one UTF-8 bytes - *utf8_output++ = char(word); + *utf8Output++ = static_cast(word); pos++; } else if ((word & 0xFFFFF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 6) | 0b11000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 6) | 0b11000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xFFFF0000) == 0) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX if (word >= 0xD800 && word <= 0xDFFF) { - return result(error_code::SURROGATE, pos); + return {error_code::SURROGATE, pos}; } - *utf8_output++ = char((word >> 12) | 0b11100000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 12) | 0b11100000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else { // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX if (word > 0x10FFFF) { - return result(error_code::TOO_LARGE, pos); + return {error_code::TOO_LARGE, pos}; } - *utf8_output++ = char((word >> 18) | 0b11110000); - *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 18) | 0b11110000); + *utf8Output++ = static_cast(((word >> 12) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } } - return result(error_code::SUCCESS, utf8_output - start); + return result(error_code::SUCCESS, utf8Output - start); } } // namespace utf32_to_utf8 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf32_to_utf8/utf32_to_utf8.h */ @@ -3497,20 +3333,17 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, #ifndef SIMDUTF_VALID_UTF32_TO_UTF8_H #define SIMDUTF_VALID_UTF32_TO_UTF8_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf32_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf32 && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf32 && simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, - OutputPtr utf8_output) { +simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { size_t pos = 0; - auto start = utf8_output; + auto start = utf8Output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -3518,52 +3351,51 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, { // try to convert the next block of 2 ASCII characters if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0xFFFFFF80FFFFFF80) == 0) { - *utf8_output++ = char(data[pos]); - *utf8_output++ = char(data[pos + 1]); - pos += 2; - continue; - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF80FFFFFF80) == 0) { + *utf8Output++ = char(data[pos]); + *utf8Output++ = char(data[pos + 1]); + pos += 2; + continue; + } } } uint32_t word = data[pos]; if ((word & 0xFFFFFF80) == 0) { // will generate one UTF-8 bytes - *utf8_output++ = char(word); + *utf8Output++ = static_cast(word); pos++; } else if ((word & 0xFFFFF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 6) | 0b11000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 6) | 0b11000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xFFFF0000) == 0) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 12) | 0b11100000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 12) | 0b11100000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } else { // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - *utf8_output++ = char((word >> 18) | 0b11110000); - *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); - *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); - *utf8_output++ = char((word & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word >> 18) | 0b11110000); + *utf8Output++ = static_cast(((word >> 12) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); + *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); pos++; } } - return utf8_output - start; + return utf8Output - start; } } // namespace utf32_to_utf8 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf32_to_utf8/valid_utf32_to_utf8.h */ @@ -3571,39 +3403,36 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, #ifndef SIMDUTF_UTF8_H #define SIMDUTF_UTF8_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf8 { // credit: based on code from Google Fuchsia (Apache Licensed) template -simdutf_constexpr23 simdutf_warn_unused bool validate(BytePtr data, - size_t len) noexcept { - static_assert( - std::is_same::type, uint8_t>::value, - "dereferencing the data pointer must result in a uint8_t"); - uint64_t pos = 0; - uint32_t code_point = 0; - while (pos < len) { - uint64_t next_pos; +simdutf_constexpr23 simdutf_warn_unused auto validate(BytePtr data, size_t len) noexcept -> bool { + static_assert(std::is_same_v, uint8_t>, + "dereferencing the data pointer must result in a uint8_t"); + uint64_t pos = 0; + uint32_t codePoint = 0; + while (pos < len) { + uint64_t nextPos = 0; #if SIMDUTF_CPLUSPLUS23 if !consteval #endif { // check if the next 16 bytes are ascii. - next_pos = pos + 16; - if (next_pos <= len) { // if it is safe to read 16 more bytes, check - // that they are ascii - uint64_t v1{}; - std::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2{}; - std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - pos = next_pos; - continue; + nextPos = pos + 16; + if (nextPos <= len) { // if it is safe to read 16 more bytes, check + // that they are ascii + uint64_t v1{}; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2{}; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + pos = nextPos; + continue; + } } - } } unsigned char byte = data[pos]; @@ -3616,23 +3445,23 @@ simdutf_constexpr23 simdutf_warn_unused bool validate(BytePtr data, } if ((byte & 0b11100000) == 0b11000000) { - next_pos = pos + 2; - if (next_pos > len) { - return false; - } + nextPos = pos + 2; + if (nextPos > len) { + return false; + } if ((data[pos + 1] & 0b11000000) != 0b10000000) { return false; } // range check - code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); - if ((code_point < 0x80) || (0x7ff < code_point)) { - return false; + codePoint = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); + if ((codePoint < 0x80) || (0x7ff < codePoint)) { + return false; } } else if ((byte & 0b11110000) == 0b11100000) { - next_pos = pos + 3; - if (next_pos > len) { - return false; - } + nextPos = pos + 3; + if (nextPos > len) { + return false; + } if ((data[pos + 1] & 0b11000000) != 0b10000000) { return false; } @@ -3640,18 +3469,15 @@ simdutf_constexpr23 simdutf_warn_unused bool validate(BytePtr data, return false; } // range check - code_point = (byte & 0b00001111) << 12 | - (data[pos + 1] & 0b00111111) << 6 | - (data[pos + 2] & 0b00111111); - if ((code_point < 0x800) || (0xffff < code_point) || - (0xd7ff < code_point && code_point < 0xe000)) { - return false; + codePoint = (byte & 0b00001111) << 12 | (data[pos + 1] & 0b00111111) << 6 | (data[pos + 2] & 0b00111111); + if ((codePoint < 0x800) || (0xffff < codePoint) || (0xd7ff < codePoint && codePoint < 0xe000)) { + return false; } } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 - next_pos = pos + 4; - if (next_pos > len) { - return false; - } + nextPos = pos + 4; + if (nextPos > len) { + return false; + } if ((data[pos + 1] & 0b11000000) != 0b10000000) { return false; } @@ -3662,132 +3488,122 @@ simdutf_constexpr23 simdutf_warn_unused bool validate(BytePtr data, return false; } // range check - code_point = - (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | - (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); - if (code_point <= 0xffff || 0x10ffff < code_point) { - return false; + codePoint = (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | (data[pos + 2] & 0b00111111) << 6 | + (data[pos + 3] & 0b00111111); + if (codePoint <= 0xffff || 0x10ffff < codePoint) { + return false; } } else { // we may have a continuation return false; } - pos = next_pos; + pos = nextPos; } return true; } -simdutf_really_inline simdutf_warn_unused bool validate(const char *buf, - size_t len) noexcept { - return validate(reinterpret_cast(buf), len); +simdutf_really_inline simdutf_warn_unused auto validate(const char* buf, size_t len) noexcept -> bool { + return validate(reinterpret_cast(buf), len); } template -simdutf_constexpr23 simdutf_warn_unused result -validate_with_errors(BytePtr data, size_t len) noexcept { - static_assert( - std::is_same::type, uint8_t>::value, - "dereferencing the data pointer must result in a uint8_t"); - size_t pos = 0; - uint32_t code_point = 0; - while (pos < len) { - // check of the next 16 bytes are ascii. - size_t next_pos = pos + 16; - if (next_pos <= - len) { // if it is safe to read 16 more bytes, check that they are ascii - uint64_t v1; - std::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - pos = next_pos; - continue; - } - } - unsigned char byte = data[pos]; +simdutf_constexpr23 simdutf_warn_unused auto validate_with_errors(BytePtr data, size_t len) noexcept -> result { + static_assert(std::is_same_v, uint8_t>, + "dereferencing the data pointer must result in a uint8_t"); + size_t pos = 0; + uint32_t codePoint = 0; + while (pos < len) { + // check of the next 16 bytes are ascii. + size_t nextPos = pos + 16; + if (nextPos <= len) { // if it is safe to read 16 more bytes, check that they are ascii + uint64_t v1 = 0; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + pos = nextPos; + continue; + } + } + unsigned char byte = data[pos]; - while (byte < 0b10000000) { - if (++pos == len) { - return result(error_code::SUCCESS, len); - } - byte = data[pos]; - } + while (byte < 0b10000000) { + if (++pos == len) { + return {error_code::SUCCESS, len}; + } + byte = data[pos]; + } - if ((byte & 0b11100000) == 0b11000000) { - next_pos = pos + 2; - if (next_pos > len) { - return result(error_code::TOO_SHORT, pos); - } - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - // range check - code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); - if ((code_point < 0x80) || (0x7ff < code_point)) { - return result(error_code::OVERLONG, pos); - } - } else if ((byte & 0b11110000) == 0b11100000) { - next_pos = pos + 3; - if (next_pos > len) { - return result(error_code::TOO_SHORT, pos); - } - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((data[pos + 2] & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - // range check - code_point = (byte & 0b00001111) << 12 | - (data[pos + 1] & 0b00111111) << 6 | - (data[pos + 2] & 0b00111111); - if ((code_point < 0x800) || (0xffff < code_point)) { - return result(error_code::OVERLONG, pos); - } - if (0xd7ff < code_point && code_point < 0xe000) { - return result(error_code::SURROGATE, pos); - } - } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 - next_pos = pos + 4; - if (next_pos > len) { - return result(error_code::TOO_SHORT, pos); - } - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((data[pos + 2] & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((data[pos + 3] & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - // range check - code_point = - (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | - (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); - if (code_point <= 0xffff) { - return result(error_code::OVERLONG, pos); - } - if (0x10ffff < code_point) { - return result(error_code::TOO_LARGE, pos); - } - } else { - // we either have too many continuation bytes or an invalid leading byte - if ((byte & 0b11000000) == 0b10000000) { - return result(error_code::TOO_LONG, pos); - } else { - return result(error_code::HEADER_BITS, pos); - } + if ((byte & 0b11100000) == 0b11000000) { + nextPos = pos + 2; + if (nextPos > len) { + return {error_code::TOO_SHORT, pos}; + } + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + // range check + codePoint = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); + if ((codePoint < 0x80) || (0x7ff < codePoint)) { + return {error_code::OVERLONG, pos}; + } + } else if ((byte & 0b11110000) == 0b11100000) { + nextPos = pos + 3; + if (nextPos > len) { + return {error_code::TOO_SHORT, pos}; + } + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + // range check + codePoint = (byte & 0b00001111) << 12 | (data[pos + 1] & 0b00111111) << 6 | (data[pos + 2] & 0b00111111); + if ((codePoint < 0x800) || (0xffff < codePoint)) { + return {error_code::OVERLONG, pos}; + } + if (0xd7ff < codePoint && codePoint < 0xe000) { + return {error_code::SURROGATE, pos}; + } + } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 + nextPos = pos + 4; + if (nextPos > len) { + return {error_code::TOO_SHORT, pos}; + } + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((data[pos + 3] & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + // range check + codePoint = (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | + (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); + if (codePoint <= 0xffff) { + return {error_code::OVERLONG, pos}; + } + if (0x10ffff < codePoint) { + return {error_code::TOO_LARGE, pos}; + } + } else { + // we either have too many continuation bytes or an invalid leading byte + if ((byte & 0b11000000) == 0b10000000) { + return {error_code::TOO_LONG, pos}; + } + return result(error_code::HEADER_BITS, pos); + } + pos = nextPos; } - pos = next_pos; - } - return result(error_code::SUCCESS, len); + return {error_code::SUCCESS, len}; } -simdutf_really_inline simdutf_warn_unused result -validate_with_errors(const char *buf, size_t len) noexcept { - return validate_with_errors(reinterpret_cast(buf), len); +simdutf_really_inline simdutf_warn_unused auto validate_with_errors(const char* buf, size_t len) noexcept -> result { + return validate_with_errors(reinterpret_cast(buf), len); } // Finds the previous leading byte starting backward from buf and validates with @@ -3795,34 +3611,33 @@ validate_with_errors(const char *buf, size_t len) noexcept { // chunk is detected We assume that the stream starts with a leading byte, and // to check that it is the case, we ask that you pass a pointer to the start of // the stream (start). -inline simdutf_warn_unused result rewind_and_validate_with_errors( - const char *start, const char *buf, size_t len) noexcept { - // First check that we start with a leading byte - if ((*start & 0b11000000) == 0b10000000) { - return result(error_code::TOO_LONG, 0); - } - size_t extra_len{0}; - // A leading byte cannot be further than 4 bytes away - for (int i = 0; i < 5; i++) { - unsigned char byte = *buf; - if ((byte & 0b11000000) != 0b10000000) { - break; - } else { - buf--; - extra_len++; +inline simdutf_warn_unused auto rewind_and_validate_with_errors(const char* start, const char* buf, size_t len) noexcept + -> result { + // First check that we start with a leading byte + if ((*start & 0b11000000) == 0b10000000) { + return {error_code::TOO_LONG, 0}; + } + size_t extra_len{0}; + // A leading byte cannot be further than 4 bytes away + for (int i = 0; i < 5; i++) { + unsigned char byte = *buf; + if ((byte & 0b11000000) != 0b10000000) { + break; + } + buf--; + extra_len++; } - } - result res = validate_with_errors(buf, len + extra_len); - res.count -= extra_len; - return res; + result res = validate_with_errors(buf, len + extra_len); + res.count -= extra_len; + return res; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t count_code_points(InputPtr data, size_t len) { +simdutf_constexpr23 auto count_code_points(InputPtr data, size_t len) -> size_t { size_t counter{0}; for (size_t i = 0; i < len; i++) { // -65 is 0b10111111, anything larger in two-complement's should start a new @@ -3836,9 +3651,9 @@ simdutf_constexpr23 size_t count_code_points(InputPtr data, size_t len) { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t utf16_length_from_utf8(InputPtr data, size_t len) { +simdutf_constexpr23 auto utf16_length_from_utf8(InputPtr data, size_t len) -> size_t { size_t counter{0}; for (size_t i = 0; i < len; i++) { if (int8_t(data[i]) > -65) { @@ -3853,10 +3668,9 @@ simdutf_constexpr23 size_t utf16_length_from_utf8(InputPtr data, size_t len) { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_warn_unused simdutf_constexpr23 size_t -trim_partial_utf8(InputPtr input, size_t length) { +simdutf_warn_unused simdutf_constexpr23 auto trim_partial_utf8(InputPtr input, size_t length) -> size_t { if (length < 3) { switch (length) { case 2: @@ -3890,8 +3704,7 @@ trim_partial_utf8(InputPtr input, size_t length) { } // namespace utf8 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf8.h */ @@ -3899,20 +3712,17 @@ trim_partial_utf8(InputPtr input, size_t length) { #ifndef SIMDUTF_UTF8_TO_LATIN1_H #define SIMDUTF_UTF8_TO_LATIN1_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf8_to_latin1 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_byte_like && - simdutf::detail::indexes_into_byte_like) + requires(simdutf::detail::indexes_into_byte_like && simdutf::detail::indexes_into_byte_like) #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - OutputPtr latin_output) { +simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr latinOutput) -> size_t { size_t pos = 0; - auto start = latin_output; + auto start = latinOutput; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -3922,72 +3732,68 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 // 1000 1000 .... etc if ((v & 0x8080808080808080) == 0) { // if NONE of these are set, e.g. all of them are zero, then // everything is ASCII - size_t final_pos = pos + 16; - while (pos < final_pos) { - *latin_output++ = char(data[pos]); - pos++; - } + size_t finalPos = pos + 16; + while (pos < finalPos) { + *latinOutput++ = char(data[pos]); + pos++; + } continue; } } } // suppose it is not an all ASCII byte sequence - uint8_t leading_byte = data[pos]; // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *latin_output++ = char(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == - 0b11000000) { // the first three bits indicate: - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } // checks if the next byte is a valid continuation byte in UTF-8. A + uint8_t leadingByte = data[pos]; // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *latinOutput++ = static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { // the first three bits indicate: + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } // checks if the next byte is a valid continuation byte in UTF-8. A // valid continuation byte starts with 10. // range check - - uint32_t code_point = - (leading_byte & 0b00011111) << 6 | - (data[pos + 1] & - 0b00111111); // assembles the Unicode code point from the two bytes. - // It does this by discarding the leading 110 and 10 - // bits from the two bytes, shifting the remaining bits - // of the first byte, and then combining the results - // with a bitwise OR operation. - if (code_point < 0x80 || 0xFF < code_point) { - return 0; // We only care about the range 129-255 which is Non-ASCII - // latin1 characters. A code_point beneath 0x80 is invalid as - // it is already covered by bytes whose leading bit is zero. - } - *latin_output++ = char(code_point); - pos += 2; + uint32_t codePoint = (leadingByte & 0b00011111) << 6 | + (data[pos + 1] & 0b00111111); // assembles the Unicode code point from the two bytes. + // It does this by discarding the leading 110 and 10 + // bits from the two bytes, shifting the remaining bits + // of the first byte, and then combining the results + // with a bitwise OR operation. + if (codePoint < 0x80 || 0xFF < codePoint) { + return 0; // We only care about the range 129-255 which is Non-ASCII + // latin1 characters. A code_point beneath 0x80 is invalid as + // it is already covered by bytes whose leading bit is zero. + } + *latinOutput++ = static_cast(codePoint); + pos += 2; } else { - return 0; + return 0; } } - return latin_output - start; + return latinOutput - start; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, - char *latin_output) { +simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char* latinOutput) -> result { size_t pos = 0; - char *start{latin_output}; + char* start{latinOutput}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -3997,128 +3803,123 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 // 1000 1000...etc if ((v & 0x8080808080808080) == 0) { // if NONE of these are set, e.g. all of them are zero, then // everything is ASCII - size_t final_pos = pos + 16; - while (pos < final_pos) { - *latin_output++ = char(data[pos]); - pos++; - } + size_t finalPos = pos + 16; + while (pos < finalPos) { + *latinOutput++ = char(data[pos]); + pos++; + } continue; } } } // suppose it is not an all ASCII byte sequence - uint8_t leading_byte = data[pos]; // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *latin_output++ = char(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == - 0b11000000) { // the first three bits indicate: - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - return result(error_code::TOO_SHORT, pos); - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } // checks if the next byte is a valid continuation byte in UTF-8. A + uint8_t leadingByte = data[pos]; // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *latinOutput++ = static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { // the first three bits indicate: + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return {error_code::TOO_SHORT, pos}; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } // checks if the next byte is a valid continuation byte in UTF-8. A // valid continuation byte starts with 10. // range check - - uint32_t code_point = - (leading_byte & 0b00011111) << 6 | - (data[pos + 1] & - 0b00111111); // assembles the Unicode code point from the two bytes. - // It does this by discarding the leading 110 and 10 - // bits from the two bytes, shifting the remaining bits - // of the first byte, and then combining the results - // with a bitwise OR operation. - if (code_point < 0x80) { - return result(error_code::OVERLONG, pos); - } - if (0xFF < code_point) { - return result(error_code::TOO_LARGE, pos); - } // We only care about the range 129-255 which is Non-ASCII latin1 + uint32_t codePoint = (leadingByte & 0b00011111) << 6 | + (data[pos + 1] & 0b00111111); // assembles the Unicode code point from the two bytes. + // It does this by discarding the leading 110 and 10 + // bits from the two bytes, shifting the remaining bits + // of the first byte, and then combining the results + // with a bitwise OR operation. + if (codePoint < 0x80) { + return {error_code::OVERLONG, pos}; + } + if (0xFF < codePoint) { + return {error_code::TOO_LARGE, pos}; + } // We only care about the range 129-255 which is Non-ASCII latin1 // characters - *latin_output++ = char(code_point); - pos += 2; - } else if ((leading_byte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8 - return result(error_code::TOO_LARGE, pos); - } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - return result(error_code::TOO_LARGE, pos); + *latinOutput++ = static_cast(codePoint); + pos += 2; + } else if ((leadingByte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + return {error_code::TOO_LARGE, pos}; + } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + return {error_code::TOO_LARGE, pos}; } else { - // we either have too many continuation bytes or an invalid leading byte - if ((leading_byte & 0b11000000) == 0b10000000) { - return result(error_code::TOO_LONG, pos); - } + // we either have too many continuation bytes or an invalid leading byte + if ((leadingByte & 0b11000000) == 0b10000000) { + return {error_code::TOO_LONG, pos}; + } - return result(error_code::HEADER_BITS, pos); - } - } - return result(error_code::SUCCESS, latin_output - start); -} - -inline result rewind_and_convert_with_errors(size_t prior_bytes, - const char *buf, size_t len, - char *latin1_output) { - size_t extra_len{0}; - // We potentially need to go back in time and find a leading byte. - // In theory '3' would be sufficient, but sometimes the error can go back - // quite far. - size_t how_far_back = prior_bytes; - // size_t how_far_back = 3; // 3 bytes in the past + current position - // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } - bool found_leading_bytes{false}; - // important: it is i <= how_far_back and not 'i < how_far_back'. - for (size_t i = 0; i <= how_far_back; i++) { - unsigned char byte = buf[-static_cast(i)]; - found_leading_bytes = ((byte & 0b11000000) != 0b10000000); - if (found_leading_bytes) { - if (i > 0 && byte < 128) { - // If we had to go back and the leading byte is ascii - // then we can stop right away. - return result(error_code::TOO_LONG, 0 - i + 1); - } - buf -= i; - extra_len = i; - break; + return {error_code::HEADER_BITS, pos}; } } - // - // It is possible for this function to return a negative count in its result. - // C++ Standard Section 18.1 defines size_t is in which is described - // in C Standard as . C Standard Section 4.1.5 defines size_t as an - // unsigned integral type of the result of the sizeof operator - // - // An unsigned type will simply wrap round arithmetically (well defined). - // - if (!found_leading_bytes) { - // If how_far_back == 3, we may have four consecutive continuation bytes!!! - // [....] [continuation] [continuation] [continuation] | [buf is - // continuation] Or we possibly have a stream that does not start with a - // leading byte. - return result(error_code::TOO_LONG, 0 - how_far_back); - } - result res = convert_with_errors(buf, len + extra_len, latin1_output); - if (res.error) { - res.count -= extra_len; - } - return res; + return {error_code::SUCCESS, latinOutput - start}; +} + +inline auto rewind_and_convert_with_errors(size_t priorBytes, const char* buf, size_t len, char* latin1Output) + -> result { + size_t extraLen{0}; + // We potentially need to go back in time and find a leading byte. + // In theory '3' would be sufficient, but sometimes the error can go back + // quite far. + size_t howFarBack = priorBytes; + // size_t how_far_back = 3; // 3 bytes in the past + current position + // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } + bool foundLeadingBytes{false}; + // important: it is i <= how_far_back and not 'i < how_far_back'. + for (size_t i = 0; i <= howFarBack; i++) { + unsigned char byte = buf[-static_cast(i)]; + foundLeadingBytes = ((byte & 0b11000000) != 0b10000000); + if (foundLeadingBytes) { + if (i > 0 && byte < 128) { + // If we had to go back and the leading byte is ascii + // then we can stop right away. + return {error_code::TOO_LONG, 0 - i + 1}; + } + buf -= i; + extraLen = i; + break; + } + } + // + // It is possible for this function to return a negative count in its result. + // C++ Standard Section 18.1 defines size_t is in which is described + // in C Standard as . C Standard Section 4.1.5 defines size_t as an + // unsigned integral type of the result of the sizeof operator + // + // An unsigned type will simply wrap round arithmetically (well defined). + // + if (!foundLeadingBytes) { + // If how_far_back == 3, we may have four consecutive continuation bytes!!! + // [....] [continuation] [continuation] [continuation] | [buf is + // continuation] Or we possibly have a stream that does not start with a + // leading byte. + return {error_code::TOO_LONG, 0 - howFarBack}; + } + result res = convert_with_errors(buf, len + extraLen, latin1Output); + if (res.error != 0) { + res.count -= extraLen; + } + return res; } } // namespace utf8_to_latin1 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf8_to_latin1/utf8_to_latin1.h */ @@ -4126,20 +3927,18 @@ inline result rewind_and_convert_with_errors(size_t prior_bytes, #ifndef SIMDUTF_VALID_UTF8_TO_LATIN1_H #define SIMDUTF_VALID_UTF8_TO_LATIN1_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf8_to_latin1 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, - char *latin_output) { +simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char* latinOutput) -> size_t { size_t pos = 0; - char *start{latin_output}; + char* start{latinOutput}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -4149,65 +3948,60 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | - v2}; // We are only interested in these bits: 1000 1000 1000 - // 1000, so it makes sense to concatenate everything - if ((v & 0x8080808080808080) == - 0) { // if NONE of these are set, e.g. all of them are zero, then - // everything is ASCII - size_t final_pos = pos + 16; - while (pos < final_pos) { - *latin_output++ = uint8_t(data[pos]); - pos++; - } - continue; - } + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 1000 + // 1000, so it makes sense to concatenate everything + if ((v & 0x8080808080808080) == + 0) { // if NONE of these are set, e.g. all of them are zero, then + // everything is ASCII + size_t finalPos = pos + 16; + while (pos < finalPos) { + *latinOutput++ = uint8_t(data[pos]); + pos++; + } + continue; + } } } // suppose it is not an all ASCII byte sequence - auto leading_byte = uint8_t(data[pos]); // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *latin_output++ = char(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == - 0b11000000) { // the first three bits indicate: - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - break; - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return 0; - } // checks if the next byte is a valid continuation byte in UTF-8. A + auto leadingByte = uint8_t(data[pos]); // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *latinOutput++ = static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { // the first three bits indicate: + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + break; + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return 0; + } // checks if the next byte is a valid continuation byte in UTF-8. A // valid continuation byte starts with 10. // range check - - uint32_t code_point = - (leading_byte & 0b00011111) << 6 | - (uint8_t(data[pos + 1]) & - 0b00111111); // assembles the Unicode code point from the two bytes. - // It does this by discarding the leading 110 and 10 - // bits from the two bytes, shifting the remaining bits - // of the first byte, and then combining the results - // with a bitwise OR operation. - *latin_output++ = char(code_point); - pos += 2; + uint32_t codePoint = (leadingByte & 0b00011111) << 6 | + (uint8_t(data[pos + 1]) & 0b00111111); // assembles the Unicode code point from the two bytes. + // It does this by discarding the leading 110 and 10 + // bits from the two bytes, shifting the remaining bits + // of the first byte, and then combining the results + // with a bitwise OR operation. + *latinOutput++ = static_cast(codePoint); + pos += 2; } else { - // we may have a continuation but we do not do error checking - return 0; + // we may have a continuation but we do not do error checking + return 0; } } - return latin_output - start; + return latinOutput - start; } } // namespace utf8_to_latin1 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf8_to_latin1/valid_utf8_to_latin1.h */ @@ -4215,19 +4009,17 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, #ifndef SIMDUTF_UTF8_TO_UTF16_H #define SIMDUTF_UTF8_TO_UTF16_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf8_to_utf16 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - char16_t *utf16_output) { +simdutf_constexpr23 auto convert(InputPtr data, size_t len, char16_t* utf16Output) -> size_t { size_t pos = 0; - char16_t *start{utf16_output}; + char16_t* start{utf16Output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4236,125 +4028,117 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, { if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - size_t final_pos = pos + 16; - while (pos < final_pos) { - *utf16_output++ = !match_system(big_endian) - ? char16_t(u16_swap_bytes(data[pos])) - : char16_t(data[pos]); - pos++; - } - continue; - } + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t finalPos = pos + 16; + while (pos < finalPos) { + *utf16Output++ = !match_system(big_endian) ? char16_t(u16_swap_bytes(data[pos])) + : char16_t(data[pos]); + pos++; + } + continue; + } } } - uint8_t leading_byte = data[pos]; // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *utf16_output++ = !match_system(big_endian) - ? char16_t(u16_swap_bytes(leading_byte)) - : char16_t(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } - // range check - uint32_t code_point = - (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); - if (code_point < 0x80 || 0x7ff < code_point) { - return 0; - } - if constexpr (!match_system(big_endian)) { - code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); - } - *utf16_output++ = char16_t(code_point); - pos += 2; - } else if ((leading_byte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 2 >= len) { - return 0; - } // minimal bound checking - - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } - if ((data[pos + 2] & 0b11000000) != 0b10000000) { - return 0; - } - // range check - uint32_t code_point = (leading_byte & 0b00001111) << 12 | - (data[pos + 1] & 0b00111111) << 6 | - (data[pos + 2] & 0b00111111); - if (code_point < 0x800 || 0xffff < code_point || - (0xd7ff < code_point && code_point < 0xe000)) { - return 0; - } - if constexpr (!match_system(big_endian)) { - code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); - } - *utf16_output++ = char16_t(code_point); - pos += 3; - } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - return 0; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } - if ((data[pos + 2] & 0b11000000) != 0b10000000) { - return 0; - } - if ((data[pos + 3] & 0b11000000) != 0b10000000) { - return 0; - } + uint8_t leadingByte = data[pos]; // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *utf16Output++ = !match_system(big_endian) ? static_cast(u16_swap_bytes(leadingByte)) + : static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t codePoint = (leadingByte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); + if (codePoint < 0x80 || 0x7ff < codePoint) { + return 0; + } + if constexpr (!match_system(big_endian)) { + codePoint = static_cast(u16_swap_bytes(static_cast(codePoint))); + } + *utf16Output++ = static_cast(codePoint); + pos += 2; + } else if ((leadingByte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 2 >= len) { + return 0; + } // minimal bound checking + + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t codePoint = + (leadingByte & 0b00001111) << 12 | (data[pos + 1] & 0b00111111) << 6 | (data[pos + 2] & 0b00111111); + if (codePoint < 0x800 || 0xffff < codePoint || (0xd7ff < codePoint && codePoint < 0xe000)) { + return 0; + } + if constexpr (!match_system(big_endian)) { + codePoint = static_cast(u16_swap_bytes(static_cast(codePoint))); + } + *utf16Output++ = static_cast(codePoint); + pos += 3; + } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 3] & 0b11000000) != 0b10000000) { + return 0; + } - // range check - uint32_t code_point = (leading_byte & 0b00000111) << 18 | - (data[pos + 1] & 0b00111111) << 12 | - (data[pos + 2] & 0b00111111) << 6 | - (data[pos + 3] & 0b00111111); - if (code_point <= 0xffff || 0x10ffff < code_point) { - return 0; - } - code_point -= 0x10000; - uint16_t high_surrogate = uint16_t(0xD800 + (code_point >> 10)); - uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); - if constexpr (!match_system(big_endian)) { - high_surrogate = u16_swap_bytes(high_surrogate); - low_surrogate = u16_swap_bytes(low_surrogate); - } - *utf16_output++ = char16_t(high_surrogate); - *utf16_output++ = char16_t(low_surrogate); - pos += 4; + // range check + uint32_t codePoint = (leadingByte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | + (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); + if (codePoint <= 0xffff || 0x10ffff < codePoint) { + return 0; + } + codePoint -= 0x10000; + auto highSurrogate = static_cast(0xD800 + (codePoint >> 10)); + auto lowSurrogate = static_cast(0xDC00 + (codePoint & 0x3FF)); + if constexpr (!match_system(big_endian)) { + highSurrogate = u16_swap_bytes(highSurrogate); + lowSurrogate = u16_swap_bytes(lowSurrogate); + } + *utf16Output++ = static_cast(highSurrogate); + *utf16Output++ = static_cast(lowSurrogate); + pos += 4; } else { - return 0; + return 0; } } - return utf16_output - start; + return utf16Output - start; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, - char16_t *utf16_output) { +simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char16_t* utf16Output) -> result { size_t pos = 0; - char16_t *start{utf16_output}; + char16_t* start{utf16Output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4363,125 +4147,118 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - size_t final_pos = pos + 16; - while (pos < final_pos) { - const char16_t byte = uint8_t(data[pos]); - *utf16_output++ = - !match_system(big_endian) ? u16_swap_bytes(byte) : byte; - pos++; - } - continue; - } + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t finalPos = pos + 16; + while (pos < finalPos) { + const char16_t byte = uint8_t(data[pos]); + *utf16Output++ = !match_system(big_endian) ? u16_swap_bytes(byte) : byte; + pos++; + } + continue; + } } } - auto leading_byte = uint8_t(data[pos]); // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *utf16_output++ = !match_system(big_endian) - ? char16_t(u16_swap_bytes(leading_byte)) - : char16_t(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 1 >= len) { - return result(error_code::TOO_SHORT, pos); - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - // range check - uint32_t code_point = (leading_byte & 0b00011111) << 6 | - (uint8_t(data[pos + 1]) & 0b00111111); - if (code_point < 0x80 || 0x7ff < code_point) { - return result(error_code::OVERLONG, pos); - } - if constexpr (!match_system(big_endian)) { - code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); - } - *utf16_output++ = char16_t(code_point); - pos += 2; - } else if ((leading_byte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 2 >= len) { - return result(error_code::TOO_SHORT, pos); - } // minimal bound checking - - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - // range check - uint32_t code_point = (leading_byte & 0b00001111) << 12 | - (uint8_t(data[pos + 1]) & 0b00111111) << 6 | - (uint8_t(data[pos + 2]) & 0b00111111); - if ((code_point < 0x800) || (0xffff < code_point)) { - return result(error_code::OVERLONG, pos); - } - if (0xd7ff < code_point && code_point < 0xe000) { - return result(error_code::SURROGATE, pos); - } - if constexpr (!match_system(big_endian)) { - code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); - } - *utf16_output++ = char16_t(code_point); - pos += 3; - } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - return result(error_code::TOO_SHORT, pos); - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } + auto leadingByte = uint8_t(data[pos]); // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *utf16Output++ = !match_system(big_endian) ? static_cast(u16_swap_bytes(leadingByte)) + : static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 1 >= len) { + return {error_code::TOO_SHORT, pos}; + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + // range check + uint32_t codePoint = (leadingByte & 0b00011111) << 6 | (uint8_t(data[pos + 1]) & 0b00111111); + if (codePoint < 0x80 || 0x7ff < codePoint) { + return {error_code::OVERLONG, pos}; + } + if constexpr (!match_system(big_endian)) { + codePoint = static_cast(u16_swap_bytes(static_cast(codePoint))); + } + *utf16Output++ = static_cast(codePoint); + pos += 2; + } else if ((leadingByte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 2 >= len) { + return {error_code::TOO_SHORT, pos}; + } // minimal bound checking + + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + // range check + uint32_t codePoint = (leadingByte & 0b00001111) << 12 | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | + (uint8_t(data[pos + 2]) & 0b00111111); + if ((codePoint < 0x800) || (0xffff < codePoint)) { + return {error_code::OVERLONG, pos}; + } + if (0xd7ff < codePoint && codePoint < 0xe000) { + return {error_code::SURROGATE, pos}; + } + if constexpr (!match_system(big_endian)) { + codePoint = static_cast(u16_swap_bytes(static_cast(codePoint))); + } + *utf16Output++ = static_cast(codePoint); + pos += 3; + } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return {error_code::TOO_SHORT, pos}; + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } - // range check - uint32_t code_point = (leading_byte & 0b00000111) << 18 | - (uint8_t(data[pos + 1]) & 0b00111111) << 12 | - (uint8_t(data[pos + 2]) & 0b00111111) << 6 | - (uint8_t(data[pos + 3]) & 0b00111111); - if (code_point <= 0xffff) { - return result(error_code::OVERLONG, pos); - } - if (0x10ffff < code_point) { - return result(error_code::TOO_LARGE, pos); - } - code_point -= 0x10000; - uint16_t high_surrogate = uint16_t(0xD800 + (code_point >> 10)); - uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); - if constexpr (!match_system(big_endian)) { - high_surrogate = u16_swap_bytes(high_surrogate); - low_surrogate = u16_swap_bytes(low_surrogate); - } - *utf16_output++ = char16_t(high_surrogate); - *utf16_output++ = char16_t(low_surrogate); - pos += 4; + // range check + uint32_t codePoint = (leadingByte & 0b00000111) << 18 | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | + (uint8_t(data[pos + 2]) & 0b00111111) << 6 | (uint8_t(data[pos + 3]) & 0b00111111); + if (codePoint <= 0xffff) { + return {error_code::OVERLONG, pos}; + } + if (0x10ffff < codePoint) { + return {error_code::TOO_LARGE, pos}; + } + codePoint -= 0x10000; + auto highSurrogate = static_cast(0xD800 + (codePoint >> 10)); + auto lowSurrogate = static_cast(0xDC00 + (codePoint & 0x3FF)); + if constexpr (!match_system(big_endian)) { + highSurrogate = u16_swap_bytes(highSurrogate); + lowSurrogate = u16_swap_bytes(lowSurrogate); + } + *utf16Output++ = static_cast(highSurrogate); + *utf16Output++ = static_cast(lowSurrogate); + pos += 4; } else { - // we either have too many continuation bytes or an invalid leading byte - if ((leading_byte & 0b11000000) == 0b10000000) { - return result(error_code::TOO_LONG, pos); - } else { + // we either have too many continuation bytes or an invalid leading byte + if ((leadingByte & 0b11000000) == 0b10000000) { + return {error_code::TOO_LONG, pos}; + } return result(error_code::HEADER_BITS, pos); - } } } - return result(error_code::SUCCESS, utf16_output - start); + return {error_code::SUCCESS, utf16Output - start}; } /** @@ -4500,58 +4277,56 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, * contain in the result will be SIZE_T - 1, SIZE_T - 2, or SIZE_T - 3. */ template -inline result rewind_and_convert_with_errors(size_t prior_bytes, - const char *buf, size_t len, - char16_t *utf16_output) { - size_t extra_len{0}; - // We potentially need to go back in time and find a leading byte. - // In theory '3' would be sufficient, but sometimes the error can go back - // quite far. - size_t how_far_back = prior_bytes; - // size_t how_far_back = 3; // 3 bytes in the past + current position - // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } - bool found_leading_bytes{false}; - // important: it is i <= how_far_back and not 'i < how_far_back'. - for (size_t i = 0; i <= how_far_back; i++) { - unsigned char byte = buf[-static_cast(i)]; - found_leading_bytes = ((byte & 0b11000000) != 0b10000000); - if (found_leading_bytes) { - if (i > 0 && byte < 128) { - // If we had to go back and the leading byte is ascii - // then we can stop right away. - return result(error_code::TOO_LONG, 0 - i + 1); - } - buf -= i; - extra_len = i; - break; +inline auto rewind_and_convert_with_errors(size_t priorBytes, const char* buf, size_t len, char16_t* utf16Output) + -> result { + size_t extraLen{0}; + // We potentially need to go back in time and find a leading byte. + // In theory '3' would be sufficient, but sometimes the error can go back + // quite far. + size_t howFarBack = priorBytes; + // size_t how_far_back = 3; // 3 bytes in the past + current position + // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } + bool foundLeadingBytes{false}; + // important: it is i <= how_far_back and not 'i < how_far_back'. + for (size_t i = 0; i <= howFarBack; i++) { + unsigned char byte = buf[-static_cast(i)]; + foundLeadingBytes = ((byte & 0b11000000) != 0b10000000); + if (foundLeadingBytes) { + if (i > 0 && byte < 128) { + // If we had to go back and the leading byte is ascii + // then we can stop right away. + return {error_code::TOO_LONG, 0 - i + 1}; + } + buf -= i; + extraLen = i; + break; + } } - } - // - // It is possible for this function to return a negative count in its result. - // C++ Standard Section 18.1 defines size_t is in which is described - // in C Standard as . C Standard Section 4.1.5 defines size_t as an - // unsigned integral type of the result of the sizeof operator - // - // An unsigned type will simply wrap round arithmetically (well defined). - // - if (!found_leading_bytes) { - // If how_far_back == 3, we may have four consecutive continuation bytes!!! - // [....] [continuation] [continuation] [continuation] | [buf is - // continuation] Or we possibly have a stream that does not start with a - // leading byte. - return result(error_code::TOO_LONG, 0 - how_far_back); - } - result res = convert_with_errors(buf, len + extra_len, utf16_output); - if (res.error) { - res.count -= extra_len; - } - return res; + // + // It is possible for this function to return a negative count in its result. + // C++ Standard Section 18.1 defines size_t is in which is described + // in C Standard as . C Standard Section 4.1.5 defines size_t as an + // unsigned integral type of the result of the sizeof operator + // + // An unsigned type will simply wrap round arithmetically (well defined). + // + if (!foundLeadingBytes) { + // If how_far_back == 3, we may have four consecutive continuation bytes!!! + // [....] [continuation] [continuation] [continuation] | [buf is + // continuation] Or we possibly have a stream that does not start with a + // leading byte. + return {error_code::TOO_LONG, 0 - howFarBack}; + } + result res = convert_with_errors(buf, len + extraLen, utf16Output); + if (res.error) { + res.count -= extraLen; + } + return res; } } // namespace utf8_to_utf16 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf8_to_utf16/utf8_to_utf16.h */ @@ -4559,19 +4334,17 @@ inline result rewind_and_convert_with_errors(size_t prior_bytes, #ifndef SIMDUTF_VALID_UTF8_TO_UTF16_H #define SIMDUTF_VALID_UTF8_TO_UTF16_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf8_to_utf16 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, - char16_t *utf16_output) { +simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char16_t* utf16Output) -> size_t { size_t pos = 0; - char16_t *start{utf16_output}; + char16_t* start{utf16Output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4579,87 +4352,79 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, { // try to convert the next block of 8 ASCII bytes if (pos + 8 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0x8080808080808080) == 0) { - size_t final_pos = pos + 8; - while (pos < final_pos) { - const char16_t byte = uint8_t(data[pos]); - *utf16_output++ = - !match_system(big_endian) ? u16_swap_bytes(byte) : byte; - pos++; - } - continue; - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0x8080808080808080) == 0) { + size_t finalPos = pos + 8; + while (pos < finalPos) { + const char16_t byte = uint8_t(data[pos]); + *utf16Output++ = !match_system(big_endian) ? u16_swap_bytes(byte) : byte; + pos++; + } + continue; + } } } - auto leading_byte = uint8_t(data[pos]); // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *utf16_output++ = !match_system(big_endian) - ? char16_t(u16_swap_bytes(leading_byte)) - : char16_t(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 1 >= len) { - break; - } // minimal bound checking - uint16_t code_point = uint16_t(((leading_byte & 0b00011111) << 6) | - (uint8_t(data[pos + 1]) & 0b00111111)); - if constexpr (!match_system(big_endian)) { - code_point = u16_swap_bytes(uint16_t(code_point)); - } - *utf16_output++ = char16_t(code_point); - pos += 2; - } else if ((leading_byte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 2 >= len) { - break; - } // minimal bound checking - uint16_t code_point = - uint16_t(((leading_byte & 0b00001111) << 12) | - ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | - (uint8_t(data[pos + 2]) & 0b00111111)); - if constexpr (!match_system(big_endian)) { - code_point = u16_swap_bytes(uint16_t(code_point)); - } - *utf16_output++ = char16_t(code_point); - pos += 3; - } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - break; - } // minimal bound checking - uint32_t code_point = ((leading_byte & 0b00000111) << 18) | - ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | - ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | - (uint8_t(data[pos + 3]) & 0b00111111); - code_point -= 0x10000; - uint16_t high_surrogate = uint16_t(0xD800 + (code_point >> 10)); - uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); - if constexpr (!match_system(big_endian)) { - high_surrogate = u16_swap_bytes(high_surrogate); - low_surrogate = u16_swap_bytes(low_surrogate); - } - *utf16_output++ = char16_t(high_surrogate); - *utf16_output++ = char16_t(low_surrogate); - pos += 4; + auto leadingByte = uint8_t(data[pos]); // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *utf16Output++ = !match_system(big_endian) ? static_cast(u16_swap_bytes(leadingByte)) + : static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 1 >= len) { + break; + } // minimal bound checking + auto codePoint = uint16_t(((leadingByte & 0b00011111) << 6) | (uint8_t(data[pos + 1]) & 0b00111111)); + if constexpr (!match_system(big_endian)) { + codePoint = u16_swap_bytes(codePoint); + } + *utf16Output++ = static_cast(codePoint); + pos += 2; + } else if ((leadingByte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 2 >= len) { + break; + } // minimal bound checking + auto codePoint = uint16_t(((leadingByte & 0b00001111) << 12) | ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | + (uint8_t(data[pos + 2]) & 0b00111111)); + if constexpr (!match_system(big_endian)) { + codePoint = u16_swap_bytes(codePoint); + } + *utf16Output++ = static_cast(codePoint); + pos += 3; + } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + break; + } // minimal bound checking + uint32_t codePoint = ((leadingByte & 0b00000111) << 18) | ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | + ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | (uint8_t(data[pos + 3]) & 0b00111111); + codePoint -= 0x10000; + auto highSurrogate = static_cast(0xD800 + (codePoint >> 10)); + auto lowSurrogate = static_cast(0xDC00 + (codePoint & 0x3FF)); + if constexpr (!match_system(big_endian)) { + highSurrogate = u16_swap_bytes(highSurrogate); + lowSurrogate = u16_swap_bytes(lowSurrogate); + } + *utf16Output++ = static_cast(highSurrogate); + *utf16Output++ = static_cast(lowSurrogate); + pos += 4; } else { - // we may have a continuation but we do not do error checking - return 0; + // we may have a continuation but we do not do error checking + return 0; } } - return utf16_output - start; + return utf16Output - start; } } // namespace utf8_to_utf16 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf8_to_utf16/valid_utf8_to_utf16.h */ @@ -4667,19 +4432,17 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, #ifndef SIMDUTF_UTF8_TO_UTF32_H #define SIMDUTF_UTF8_TO_UTF32_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf8_to_utf32 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t convert(InputPtr data, size_t len, - char32_t *utf32_output) { +simdutf_constexpr23 auto convert(InputPtr data, size_t len, char32_t* utf32Output) -> size_t { size_t pos = 0; - char32_t *start{utf32_output}; + char32_t* start{utf32Output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4688,210 +4451,199 @@ simdutf_constexpr23 size_t convert(InputPtr data, size_t len, // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - size_t final_pos = pos + 16; - while (pos < final_pos) { - *utf32_output++ = uint8_t(data[pos]); - pos++; - } - continue; - } + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t finalPos = pos + 16; + while (pos < finalPos) { + *utf32Output++ = uint8_t(data[pos]); + pos++; + } + continue; + } } } - auto leading_byte = uint8_t(data[pos]); // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *utf32_output++ = char32_t(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } - // range check - uint32_t code_point = (leading_byte & 0b00011111) << 6 | - (uint8_t(data[pos + 1]) & 0b00111111); - if (code_point < 0x80 || 0x7ff < code_point) { - return 0; - } - *utf32_output++ = char32_t(code_point); - pos += 2; - } else if ((leading_byte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8 - if (pos + 2 >= len) { - return 0; - } // minimal bound checking - - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return 0; - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return 0; - } - // range check - uint32_t code_point = (leading_byte & 0b00001111) << 12 | - (uint8_t(data[pos + 1]) & 0b00111111) << 6 | - (uint8_t(data[pos + 2]) & 0b00111111); - if (code_point < 0x800 || 0xffff < code_point || - (0xd7ff < code_point && code_point < 0xe000)) { - return 0; - } - *utf32_output++ = char32_t(code_point); - pos += 3; - } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - return 0; - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return 0; - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return 0; - } - if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { - return 0; - } + auto leadingByte = uint8_t(data[pos]); // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *utf32Output++ = static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t codePoint = (leadingByte & 0b00011111) << 6 | (uint8_t(data[pos + 1]) & 0b00111111); + if (codePoint < 0x80 || 0x7ff < codePoint) { + return 0; + } + *utf32Output++ = static_cast(codePoint); + pos += 2; + } else if ((leadingByte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + if (pos + 2 >= len) { + return 0; + } // minimal bound checking + + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return 0; + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t codePoint = (leadingByte & 0b00001111) << 12 | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | + (uint8_t(data[pos + 2]) & 0b00111111); + if (codePoint < 0x800 || 0xffff < codePoint || (0xd7ff < codePoint && codePoint < 0xe000)) { + return 0; + } + *utf32Output++ = static_cast(codePoint); + pos += 3; + } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return 0; + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return 0; + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return 0; + } + if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { + return 0; + } - // range check - uint32_t code_point = (leading_byte & 0b00000111) << 18 | - (uint8_t(data[pos + 1]) & 0b00111111) << 12 | - (uint8_t(data[pos + 2]) & 0b00111111) << 6 | - (uint8_t(data[pos + 3]) & 0b00111111); - if (code_point <= 0xffff || 0x10ffff < code_point) { - return 0; - } - *utf32_output++ = char32_t(code_point); - pos += 4; + // range check + uint32_t codePoint = (leadingByte & 0b00000111) << 18 | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | + (uint8_t(data[pos + 2]) & 0b00111111) << 6 | (uint8_t(data[pos + 3]) & 0b00111111); + if (codePoint <= 0xffff || 0x10ffff < codePoint) { + return 0; + } + *utf32Output++ = static_cast(codePoint); + pos += 4; } else { - return 0; + return 0; } } - return utf32_output - start; -} - -template -#if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like -#endif -simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, - char32_t *utf32_output) { - size_t pos = 0; - char32_t *start{utf32_output}; - while (pos < len) { -#if SIMDUTF_CPLUSPLUS23 - if !consteval -#endif - { - // try to convert the next block of 16 ASCII bytes - if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that - // they are ascii - uint64_t v1; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - size_t final_pos = pos + 16; - while (pos < final_pos) { - *utf32_output++ = uint8_t(data[pos]); - pos++; - } - continue; - } - } - } - auto leading_byte = uint8_t(data[pos]); // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *utf32_output++ = char32_t(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - return result(error_code::TOO_SHORT, pos); - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - // range check - uint32_t code_point = (leading_byte & 0b00011111) << 6 | - (uint8_t(data[pos + 1]) & 0b00111111); - if (code_point < 0x80 || 0x7ff < code_point) { - return result(error_code::OVERLONG, pos); - } - *utf32_output++ = char32_t(code_point); - pos += 2; - } else if ((leading_byte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8 - if (pos + 2 >= len) { - return result(error_code::TOO_SHORT, pos); - } // minimal bound checking + return utf32Output - start; +} - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - // range check - uint32_t code_point = (leading_byte & 0b00001111) << 12 | - (uint8_t(data[pos + 1]) & 0b00111111) << 6 | - (uint8_t(data[pos + 2]) & 0b00111111); - if (code_point < 0x800 || 0xffff < code_point) { - return result(error_code::OVERLONG, pos); - } - if (0xd7ff < code_point && code_point < 0xe000) { - return result(error_code::SURROGATE, pos); - } - *utf32_output++ = char32_t(code_point); - pos += 3; - } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - return result(error_code::TOO_SHORT, pos); - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); - } - if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { - return result(error_code::TOO_SHORT, pos); +template +#if SIMDUTF_CPLUSPLUS20 + requires simdutf::detail::indexes_into_byte_like +#endif +simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char32_t* utf32Output) -> result { + size_t pos = 0; + char32_t* start{utf32Output}; + while (pos < len) { +#if SIMDUTF_CPLUSPLUS23 + if !consteval +#endif + { + // try to convert the next block of 16 ASCII bytes + if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that + // they are ascii + uint64_t v1 = 0; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2 = 0; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t finalPos = pos + 16; + while (pos < finalPos) { + *utf32Output++ = uint8_t(data[pos]); + pos++; + } + continue; + } } + } + auto leadingByte = uint8_t(data[pos]); // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *utf32Output++ = static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return {error_code::TOO_SHORT, pos}; + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + // range check + uint32_t codePoint = (leadingByte & 0b00011111) << 6 | (uint8_t(data[pos + 1]) & 0b00111111); + if (codePoint < 0x80 || 0x7ff < codePoint) { + return {error_code::OVERLONG, pos}; + } + *utf32Output++ = static_cast(codePoint); + pos += 2; + } else if ((leadingByte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + if (pos + 2 >= len) { + return {error_code::TOO_SHORT, pos}; + } // minimal bound checking + + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + // range check + uint32_t codePoint = (leadingByte & 0b00001111) << 12 | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | + (uint8_t(data[pos + 2]) & 0b00111111); + if (codePoint < 0x800 || 0xffff < codePoint) { + return {error_code::OVERLONG, pos}; + } + if (0xd7ff < codePoint && codePoint < 0xe000) { + return {error_code::SURROGATE, pos}; + } + *utf32Output++ = static_cast(codePoint); + pos += 3; + } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return {error_code::TOO_SHORT, pos}; + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } + if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { + return {error_code::TOO_SHORT, pos}; + } - // range check - uint32_t code_point = (leading_byte & 0b00000111) << 18 | - (uint8_t(data[pos + 1]) & 0b00111111) << 12 | - (uint8_t(data[pos + 2]) & 0b00111111) << 6 | - (uint8_t(data[pos + 3]) & 0b00111111); - if (code_point <= 0xffff) { - return result(error_code::OVERLONG, pos); - } - if (0x10ffff < code_point) { - return result(error_code::TOO_LARGE, pos); - } - *utf32_output++ = char32_t(code_point); - pos += 4; + // range check + uint32_t codePoint = (leadingByte & 0b00000111) << 18 | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | + (uint8_t(data[pos + 2]) & 0b00111111) << 6 | (uint8_t(data[pos + 3]) & 0b00111111); + if (codePoint <= 0xffff) { + return {error_code::OVERLONG, pos}; + } + if (0x10ffff < codePoint) { + return {error_code::TOO_LARGE, pos}; + } + *utf32Output++ = static_cast(codePoint); + pos += 4; } else { - // we either have too many continuation bytes or an invalid leading byte - if ((leading_byte & 0b11000000) == 0b10000000) { - return result(error_code::TOO_LONG, pos); - } else { + // we either have too many continuation bytes or an invalid leading byte + if ((leadingByte & 0b11000000) == 0b10000000) { + return {error_code::TOO_LONG, pos}; + } return result(error_code::HEADER_BITS, pos); - } } } - return result(error_code::SUCCESS, utf32_output - start); + return {error_code::SUCCESS, utf32Output - start}; } /** @@ -4909,58 +4661,54 @@ simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, * If the error is believed to have occurred prior to 'buf', the count value * contain in the result will be SIZE_T - 1, SIZE_T - 2, or SIZE_T - 3. */ -inline result rewind_and_convert_with_errors(size_t prior_bytes, - const char *buf, size_t len, - char32_t *utf32_output) { - size_t extra_len{0}; - // We potentially need to go back in time and find a leading byte. - size_t how_far_back = 3; // 3 bytes in the past + current position - if (how_far_back > prior_bytes) { - how_far_back = prior_bytes; - } - bool found_leading_bytes{false}; - // important: it is i <= how_far_back and not 'i < how_far_back'. - for (size_t i = 0; i <= how_far_back; i++) { - unsigned char byte = buf[-static_cast(i)]; - found_leading_bytes = ((byte & 0b11000000) != 0b10000000); - if (found_leading_bytes) { - if (i > 0 && byte < 128) { - // If we had to go back and the leading byte is ascii - // then we can stop right away. - return result(error_code::TOO_LONG, 0 - i + 1); - } - buf -= i; - extra_len = i; - break; +inline auto rewind_and_convert_with_errors(size_t prior_bytes, const char* buf, size_t len, char32_t* utf32Output) + -> result { + size_t extraLen{0}; + // We potentially need to go back in time and find a leading byte. + size_t how_far_back = 3; // 3 bytes in the past + current position + how_far_back = std::min(how_far_back, prior_bytes); + bool foundLeadingBytes{false}; + // important: it is i <= how_far_back and not 'i < how_far_back'. + for (size_t i = 0; i <= how_far_back; i++) { + unsigned char byte = buf[-static_cast(i)]; + foundLeadingBytes = ((byte & 0b11000000) != 0b10000000); + if (foundLeadingBytes) { + if (i > 0 && byte < 128) { + // If we had to go back and the leading byte is ascii + // then we can stop right away. + return {error_code::TOO_LONG, 0 - i + 1}; + } + buf -= i; + extraLen = i; + break; + } + } + // + // It is possible for this function to return a negative count in its result. + // C++ Standard Section 18.1 defines size_t is in which is described + // in C Standard as . C Standard Section 4.1.5 defines size_t as an + // unsigned integral type of the result of the sizeof operator + // + // An unsigned type will simply wrap round arithmetically (well defined). + // + if (!foundLeadingBytes) { + // If how_far_back == 3, we may have four consecutive continuation bytes!!! + // [....] [continuation] [continuation] [continuation] | [buf is + // continuation] Or we possibly have a stream that does not start with a + // leading byte. + return {error_code::TOO_LONG, 0 - how_far_back}; } - } - // - // It is possible for this function to return a negative count in its result. - // C++ Standard Section 18.1 defines size_t is in which is described - // in C Standard as . C Standard Section 4.1.5 defines size_t as an - // unsigned integral type of the result of the sizeof operator - // - // An unsigned type will simply wrap round arithmetically (well defined). - // - if (!found_leading_bytes) { - // If how_far_back == 3, we may have four consecutive continuation bytes!!! - // [....] [continuation] [continuation] [continuation] | [buf is - // continuation] Or we possibly have a stream that does not start with a - // leading byte. - return result(error_code::TOO_LONG, 0 - how_far_back); - } - result res = convert_with_errors(buf, len + extra_len, utf32_output); - if (res.error) { - res.count -= extra_len; - } - return res; + result res = convert_with_errors(buf, len + extraLen, utf32Output); + if (res.error != 0) { + res.count -= extraLen; + } + return res; } } // namespace utf8_to_utf32 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf8_to_utf32/utf8_to_utf32.h */ @@ -4968,19 +4716,17 @@ inline result rewind_and_convert_with_errors(size_t prior_bytes, #ifndef SIMDUTF_VALID_UTF8_TO_UTF32_H #define SIMDUTF_VALID_UTF8_TO_UTF32_H -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace utf8_to_utf32 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, - char32_t *utf32_output) { +simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char32_t* utf32Output) -> size_t { size_t pos = 0; - char32_t *start{utf32_output}; + char32_t* start{utf32Output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4989,71 +4735,65 @@ simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, // try to convert the next block of 8 ASCII bytes if (pos + 8 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0x8080808080808080) == 0) { - size_t final_pos = pos + 8; - while (pos < final_pos) { - *utf32_output++ = uint8_t(data[pos]); - pos++; - } - continue; - } + uint64_t v = 0; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0x8080808080808080) == 0) { + size_t finalPos = pos + 8; + while (pos < finalPos) { + *utf32Output++ = uint8_t(data[pos]); + pos++; + } + continue; + } } } - auto leading_byte = uint8_t(data[pos]); // leading byte - if (leading_byte < 0b10000000) { - // converting one ASCII byte !!! - *utf32_output++ = char32_t(leading_byte); - pos++; - } else if ((leading_byte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - break; - } // minimal bound checking - *utf32_output++ = char32_t(((leading_byte & 0b00011111) << 6) | - (uint8_t(data[pos + 1]) & 0b00111111)); - pos += 2; - } else if ((leading_byte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8 - if (pos + 2 >= len) { - break; - } // minimal bound checking - *utf32_output++ = char32_t(((leading_byte & 0b00001111) << 12) | - ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | - (uint8_t(data[pos + 2]) & 0b00111111)); - pos += 3; - } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - break; - } // minimal bound checking - uint32_t code_word = ((leading_byte & 0b00000111) << 18) | - ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | - ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | - (uint8_t(data[pos + 3]) & 0b00111111); - *utf32_output++ = char32_t(code_word); - pos += 4; + auto leadingByte = uint8_t(data[pos]); // leading byte + if (leadingByte < 0b10000000) { + // converting one ASCII byte !!! + *utf32Output++ = static_cast(leadingByte); + pos++; + } else if ((leadingByte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + break; + } // minimal bound checking + *utf32Output++ = char32_t(((leadingByte & 0b00011111) << 6) | (uint8_t(data[pos + 1]) & 0b00111111)); + pos += 2; + } else if ((leadingByte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + if (pos + 2 >= len) { + break; + } // minimal bound checking + *utf32Output++ = char32_t(((leadingByte & 0b00001111) << 12) | ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | + (uint8_t(data[pos + 2]) & 0b00111111)); + pos += 3; + } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + break; + } // minimal bound checking + uint32_t codeWord = ((leadingByte & 0b00000111) << 18) | ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | + ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | (uint8_t(data[pos + 3]) & 0b00111111); + *utf32Output++ = static_cast(codeWord); + pos += 4; } else { - // we may have a continuation but we do not do error checking - return 0; + // we may have a continuation but we do not do error checking + return 0; } } - return utf32_output - start; + return utf32Output - start; } } // namespace utf8_to_utf32 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/utf8_to_utf32/valid_utf8_to_utf32.h */ namespace simdutf { -constexpr size_t default_line_length = - 76; ///< default line length for base64 encoding with lines +constexpr size_t defaultLineLength = 76; ///< default line length for base64 encoding with lines #if SIMDUTF_FEATURE_DETECT_ENCODING /** @@ -5066,13 +4806,12 @@ constexpr size_t default_line_length = * @param length the length of the string in bytes. * @return the detected encoding type */ -simdutf_warn_unused simdutf::encoding_type -autodetect_encoding(const char *input, size_t length) noexcept; -simdutf_really_inline simdutf_warn_unused simdutf::encoding_type -autodetect_encoding(const uint8_t *input, size_t length) noexcept { - return autodetect_encoding(reinterpret_cast(input), length); +simdutf_warn_unused auto autodetect_encoding(const char* input, size_t length) noexcept -> simdutf::encoding_type; +simdutf_really_inline simdutf_warn_unused auto autodetect_encoding(const uint8_t* input, size_t length) noexcept + -> simdutf::encoding_type { + return autodetect_encoding(reinterpret_cast(input), length); } - #if SIMDUTF_SPAN +#if SIMDUTF_SPAN /** * Autodetect the encoding of the input, a single encoding is recommended. * E.g., the function might return simdutf::encoding_type::UTF8, @@ -5084,13 +4823,11 @@ autodetect_encoding(const uint8_t *input, size_t length) noexcept { * std::string_view, std::vector, std::span etc. * @return the detected encoding type */ -simdutf_really_inline simdutf_warn_unused simdutf::encoding_type -autodetect_encoding( - const detail::input_span_of_byte_like auto &input) noexcept { - return autodetect_encoding(reinterpret_cast(input.data()), - input.size()); +simdutf_really_inline simdutf_warn_unused auto autodetect_encoding( + const detail::input_span_of_byte_like auto& input) noexcept -> simdutf::encoding_type { + return autodetect_encoding(reinterpret_cast(input.data()), input.size()); } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Autodetect the possible encodings of the input in one pass. @@ -5103,19 +4840,16 @@ autodetect_encoding( * @param length the length of the string in bytes. * @return the detected encoding type */ -simdutf_warn_unused int detect_encodings(const char *input, - size_t length) noexcept; -simdutf_really_inline simdutf_warn_unused int -detect_encodings(const uint8_t *input, size_t length) noexcept { - return detect_encodings(reinterpret_cast(input), length); +simdutf_warn_unused auto detect_encodings(const char* input, size_t length) noexcept -> int; +simdutf_really_inline simdutf_warn_unused auto detect_encodings(const uint8_t* input, size_t length) noexcept -> int { + return detect_encodings(reinterpret_cast(input), length); } - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused int -detect_encodings(const detail::input_span_of_byte_like auto &input) noexcept { - return detect_encodings(reinterpret_cast(input.data()), - input.size()); +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused auto detect_encodings( + const detail::input_span_of_byte_like auto& input) noexcept -> int { + return detect_encodings(reinterpret_cast(input.data()), input.size()); } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING @@ -5130,22 +4864,21 @@ detect_encodings(const detail::input_span_of_byte_like auto &input) noexcept { * @param len the length of the string in bytes. * @return true if and only if the string is valid UTF-8. */ -simdutf_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_constexpr23 simdutf_really_inline simdutf_warn_unused bool -validate_utf8(const detail::input_span_of_byte_like auto &input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::validate( - detail::constexpr_cast_ptr(input.data()), input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf8(const char* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_constexpr23 simdutf_really_inline + simdutf_warn_unused auto validate_utf8(const detail::input_span_of_byte_like auto& input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::validate(detail::constexpr_cast_ptr(input.data()), input.size()); + } else +#endif + { return validate_utf8(reinterpret_cast(input.data()), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 @@ -5161,24 +4894,21 @@ validate_utf8(const detail::input_span_of_byte_like auto &input) noexcept { * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused result validate_utf8_with_errors(const char *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result -validate_utf8_with_errors( - const detail::input_span_of_byte_like auto &input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::validate_with_errors( - detail::constexpr_cast_ptr(input.data()), input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf8_with_errors(const char* buf, size_t len) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto validate_utf8_with_errors( + const detail::input_span_of_byte_like auto& input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::validate_with_errors(detail::constexpr_cast_ptr(input.data()), input.size()); + } else +#endif + { return validate_utf8_with_errors( reinterpret_cast(input.data()), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_ASCII @@ -5191,22 +4921,21 @@ validate_utf8_with_errors( * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ -simdutf_warn_unused bool validate_ascii(const char *buf, size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool -validate_ascii(const detail::input_span_of_byte_like auto &input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::ascii::validate( - detail::constexpr_cast_ptr(input.data()), input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_ascii(const char* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_ascii(const detail::input_span_of_byte_like auto& input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::ascii::validate(detail::constexpr_cast_ptr(input.data()), input.size()); + } else +#endif + { return validate_ascii(reinterpret_cast(input.data()), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Validate the ASCII string and stop on error. It might be faster than @@ -5221,24 +4950,22 @@ validate_ascii(const detail::input_span_of_byte_like auto &input) noexcept { * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused result validate_ascii_with_errors(const char *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -validate_ascii_with_errors( - const detail::input_span_of_byte_like auto &input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::ascii::validate_with_errors( - detail::constexpr_cast_ptr(input.data()), input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_ascii_with_errors(const char* buf, size_t len) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto validate_ascii_with_errors( + const detail::input_span_of_byte_like auto& input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::ascii::validate_with_errors(detail::constexpr_cast_ptr(input.data()), + input.size()); + } else +#endif + { return validate_ascii_with_errors( reinterpret_cast(input.data()), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII @@ -5253,22 +4980,20 @@ validate_ascii_with_errors( * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ -simdutf_warn_unused bool validate_utf16_as_ascii(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool -validate_utf16_as_ascii(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_as_ascii(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16_as_ascii(const char16_t* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf16_as_ascii(std::span input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_as_ascii(input.data(), input.size()); + } else +#endif + { return validate_utf16_as_ascii(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Validate the ASCII string as a UTF-16BE sequence. @@ -5281,22 +5006,20 @@ validate_utf16_as_ascii(std::span input) noexcept { * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ -simdutf_warn_unused bool validate_utf16be_as_ascii(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool -validate_utf16be_as_ascii(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_as_ascii(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16be_as_ascii(const char16_t* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf16be_as_ascii(std::span input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_as_ascii(input.data(), input.size()); + } else +#endif + { return validate_utf16be_as_ascii(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Validate the ASCII string as a UTF-16LE sequence. @@ -5309,22 +5032,20 @@ validate_utf16be_as_ascii(std::span input) noexcept { * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ -simdutf_warn_unused bool validate_utf16le_as_ascii(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool -validate_utf16le_as_ascii(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_as_ascii(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16le_as_ascii(const char16_t* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf16le_as_ascii(std::span input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_as_ascii(input.data(), input.size()); + } else +#endif + { return validate_utf16le_as_ascii(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 @@ -5342,22 +5063,20 @@ validate_utf16le_as_ascii(std::span input) noexcept { * (char16_t). * @return true if and only if the string is valid UTF-16. */ -simdutf_warn_unused bool validate_utf16(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool -validate_utf16(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16(const char16_t* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf16(std::span input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate(input.data(), input.size()); + } else +#endif + { return validate_utf16(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING @@ -5375,22 +5094,20 @@ validate_utf16(std::span input) noexcept { * (char16_t). * @return true if and only if the string is valid UTF-16LE. */ -simdutf_warn_unused bool validate_utf16le(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused bool -validate_utf16le(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16le(const char16_t* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 + simdutf_warn_unused auto validate_utf16le(std::span input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate(input.data(), input.size()); + } else +#endif + { return validate_utf16le(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF16 @@ -5408,21 +5125,20 @@ validate_utf16le(std::span input) noexcept { * (char16_t). * @return true if and only if the string is valid UTF-16BE. */ -simdutf_warn_unused bool validate_utf16be(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool -validate_utf16be(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate(input.data(), input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16be(const char16_t* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf16be(std::span input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate(input.data(), input.size()); + } else +#endif + { return validate_utf16be(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Using native endianness; Validate the UTF-16 string and stop on error. @@ -5441,22 +5157,20 @@ validate_utf16be(std::span input) noexcept { * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused result validate_utf16_with_errors(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -validate_utf16_with_errors(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_with_errors( - input.data(), input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16_with_errors(const char16_t* buf, size_t len) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf16_with_errors(std::span input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_with_errors(input.data(), input.size()); + } else +#endif + { return validate_utf16_with_errors(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Validate the UTF-16LE string and stop on error. It might be faster than @@ -5474,22 +5188,20 @@ validate_utf16_with_errors(std::span input) noexcept { * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused result validate_utf16le_with_errors(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -validate_utf16le_with_errors(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_with_errors( - input.data(), input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16le_with_errors(const char16_t* buf, size_t len) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf16le_with_errors(std::span input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_with_errors(input.data(), input.size()); + } else +#endif + { return validate_utf16le_with_errors(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Validate the UTF-16BE string and stop on error. It might be faster than @@ -5507,22 +5219,20 @@ validate_utf16le_with_errors(std::span input) noexcept { * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused result validate_utf16be_with_errors(const char16_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -validate_utf16be_with_errors(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_with_errors(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf16be_with_errors(const char16_t* buf, size_t len) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf16be_with_errors(std::span input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_with_errors(input.data(), input.size()); + } else +#endif + { return validate_utf16be_with_errors(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Fixes an ill-formed UTF-16LE string by replacing mismatched surrogates with @@ -5631,22 +5341,20 @@ to_well_formed_utf16(std::span input, * (char32_t). * @return true if and only if the string is valid UTF-32. */ -simdutf_warn_unused bool validate_utf32(const char32_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool -validate_utf32(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32::validate( - detail::constexpr_cast_ptr(input.data()), input.size()); - } else - #endif - { +simdutf_warn_unused auto validate_utf32(const char32_t* buf, size_t len) noexcept -> bool; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf32(std::span input) noexcept -> bool { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32::validate(detail::constexpr_cast_ptr(input.data()), input.size()); + } else +#endif + { return validate_utf32(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF32 @@ -5661,27 +5369,26 @@ validate_utf32(std::span input) noexcept { * @param buf the UTF-32 string to validate. * @param len the length of the string in number of 4-byte code units * (char32_t). - * @return a result pair struct (of type simdutf::result containing the two - * fields error and count) with an error code and either position of the error - * (in the input in code units) if any, or the number of code units validated if - * successful. - */ -simdutf_warn_unused result validate_utf32_with_errors(const char32_t *buf, - size_t len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -validate_utf32_with_errors(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32::validate_with_errors( - detail::constexpr_cast_ptr(input.data()), input.size()); - } else - #endif - { + * @return a result pair struct (of type simdutf::result containing the two + * fields error and count) with an error code and either position of the error + * (in the input in code units) if any, or the number of code units validated if + * successful. + */ +simdutf_warn_unused auto validate_utf32_with_errors(const char32_t* buf, size_t len) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto validate_utf32_with_errors(std::span input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32::validate_with_errors(detail::constexpr_cast_ptr(input.data()), + input.size()); + } else +#endif + { return validate_utf32_with_errors(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -5695,29 +5402,23 @@ validate_utf32_with_errors(std::span input) noexcept { * @param utf8_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_latin1_to_utf8(const char *input, - size_t length, - char *utf8_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_latin1_to_utf8( - const detail::input_span_of_byte_like auto &latin1_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf8::convert( - detail::constexpr_cast_ptr(latin1_input.data()), - latin1_input.size(), - detail::constexpr_cast_writeptr(utf8_output.data())); - } else - #endif - { - return convert_latin1_to_utf8( - reinterpret_cast(latin1_input.data()), - latin1_input.size(), reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_latin1_to_utf8(const char* input, size_t length, char* utf8Output) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf8( + const detail::input_span_of_byte_like auto& latin1Input, + detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf8::convert(detail::constexpr_cast_ptr(latin1Input.data()), latin1Input.size(), + detail::constexpr_cast_writeptr(utf8Output.data())); + } else +#endif + { + return convert_latin1_to_utf8(reinterpret_cast(latin1Input.data()), latin1Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert Latin1 string into UTF-8 string with output limit. @@ -5732,33 +5433,30 @@ convert_latin1_to_utf8( * @param utf8_len the maximum output length * @return the number of written char; 0 if conversion is not possible */ -simdutf_warn_unused size_t -convert_latin1_to_utf8_safe(const char *input, size_t length, char *utf8_output, - size_t utf8_len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_latin1_to_utf8_safe( - const detail::input_span_of_byte_like auto &input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - // implementation note: outputspan is a forwarding ref to avoid copying - // and allow both lvalues and rvalues. std::span can be copied without - // problems, but std::vector should not, and this function should accept - // both. it will allow using an owning rvalue ref (example: passing a - // temporary std::string) as output, but the user will quickly find out - // that he has no way of getting the data out of the object in that case. - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf8::convert_safe_constexpr( - input.data(), input.size(), utf8_output.data(), utf8_output.size()); - } else - #endif - { - return convert_latin1_to_utf8_safe( - reinterpret_cast(input.data()), input.size(), - reinterpret_cast(utf8_output.data()), utf8_output.size()); +simdutf_warn_unused auto convert_latin1_to_utf8_safe(const char* input, size_t length, char* utf8Output, + size_t utf8Len) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf8_safe( + const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& utf8Output) noexcept + -> size_t { + // implementation note: outputspan is a forwarding ref to avoid copying + // and allow both lvalues and rvalues. std::span can be copied without + // problems, but std::vector should not, and this function should accept + // both. it will allow using an owning rvalue ref (example: passing a + // temporary std::string) as output, but the user will quickly find out + // that he has no way of getting the data out of the object in that case. +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf8::convert_safe_constexpr(input.data(), input.size(), utf8Output.data(), + utf8Output.size()); + } else +#endif + { + return convert_latin1_to_utf8_safe(reinterpret_cast(input.data()), input.size(), + reinterpret_cast(utf8Output.data()), utf8Output.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -5772,26 +5470,23 @@ convert_latin1_to_utf8_safe( * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_latin1_to_utf16le( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_latin1_to_utf16le( - const detail::input_span_of_byte_like auto &latin1_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf16::convert( - latin1_input.data(), latin1_input.size(), utf16_output.data()); - } else - #endif - { - return convert_latin1_to_utf16le( - reinterpret_cast(latin1_input.data()), - latin1_input.size(), utf16_output.data()); +simdutf_warn_unused auto convert_latin1_to_utf16le(const char* input, size_t length, char16_t* utf16Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf16le( + const detail::input_span_of_byte_like auto& latin1Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf16::convert(latin1Input.data(), latin1Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_latin1_to_utf16le(reinterpret_cast(latin1Input.data()), latin1Input.size(), + utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert Latin1 string into UTF-16BE string. @@ -5803,25 +5498,23 @@ convert_latin1_to_utf16le( * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_latin1_to_utf16be( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_latin1_to_utf16be(const detail::input_span_of_byte_like auto &input, - std::span output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf16::convert( - input.data(), input.size(), output.data()); - } else - #endif - { +simdutf_warn_unused auto convert_latin1_to_utf16be(const char* input, size_t length, char16_t* utf16Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf16be( + const detail::input_span_of_byte_like auto& input, std::span output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf16::convert(input.data(), input.size(), output.data()); + } else +#endif + { return convert_latin1_to_utf16be( reinterpret_cast(input.data()), input.size(), output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16 string would require in Latin1 * format. @@ -5830,9 +5523,9 @@ convert_latin1_to_utf16be(const detail::input_span_of_byte_like auto &input, * @return the length of the string in Latin1 code units (char) required to * encode the UTF-16 string as Latin1 */ -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -latin1_length_from_utf16(size_t length) noexcept { - return length; +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto latin1_length_from_utf16(size_t length) noexcept + -> size_t { + return length; } /** @@ -5843,9 +5536,9 @@ latin1_length_from_utf16(size_t length) noexcept { * @return the length of the string in 2-byte code units (char16_t) required to * encode the Latin1 string as UTF-16 */ -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf16_length_from_latin1(size_t length) noexcept { - return length; +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf16_length_from_latin1(size_t length) noexcept + -> size_t { + return length; } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -5860,26 +5553,22 @@ utf16_length_from_latin1(size_t length) noexcept { * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_latin1_to_utf32( - const char *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_latin1_to_utf32( - const detail::input_span_of_byte_like auto &latin1_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf32::convert( - latin1_input.data(), latin1_input.size(), utf32_output.data()); - } else - #endif - { - return convert_latin1_to_utf32( - reinterpret_cast(latin1_input.data()), - latin1_input.size(), utf32_output.data()); +simdutf_warn_unused auto convert_latin1_to_utf32(const char* input, size_t length, char32_t* utf32Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf32( + const detail::input_span_of_byte_like auto& latin1Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf32::convert(latin1Input.data(), latin1Input.size(), utf32Output.data()); + } else +#endif + { + return convert_latin1_to_utf32(reinterpret_cast(latin1Input.data()), latin1Input.size(), + utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -5895,27 +5584,24 @@ convert_latin1_to_utf32( * @return the number of written char; 0 if the input was not valid UTF-8 string * or if it cannot be represented as Latin1 */ -simdutf_warn_unused size_t convert_utf8_to_latin1(const char *input, - size_t length, - char *latin1_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf8_to_latin1( - const detail::input_span_of_byte_like auto &input, - detail::output_span_of_byte_like auto &&output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_latin1::convert(input.data(), input.size(), - output.data()); - } else - #endif - { +simdutf_warn_unused auto convert_utf8_to_latin1(const char* input, size_t length, char* latin1Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_latin1( + const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& output) noexcept + -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_latin1::convert(input.data(), input.size(), output.data()); + } else +#endif + { return convert_utf8_to_latin1(reinterpret_cast(input.data()), input.size(), reinterpret_cast(output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -5932,24 +5618,22 @@ convert_utf8_to_latin1( * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ -simdutf_warn_unused size_t convert_utf8_to_utf16( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf8_to_utf16(const detail::input_span_of_byte_like auto &input, - std::span output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert( - input.data(), input.size(), output.data()); - } else - #endif - { +simdutf_warn_unused auto convert_utf8_to_utf16(const char* input, size_t length, char16_t* utf16Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16( + const detail::input_span_of_byte_like auto& input, std::span output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert(input.data(), input.size(), output.data()); + } else +#endif + { return convert_utf8_to_utf16(reinterpret_cast(input.data()), input.size(), output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-8 @@ -5968,24 +5652,22 @@ convert_utf8_to_utf16(const detail::input_span_of_byte_like auto &input, * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ -simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( - const char16_t *input, size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result -utf8_length_from_utf16le_with_replacement( - std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16_with_replacement< - endianness::LITTLE>(valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf8_length_from_utf16le_with_replacement(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf8_length_from_utf16le_with_replacement(const char16_t* input, size_t length) noexcept + -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto utf8_length_from_utf16le_with_replacement( + std::span validUtf16Input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16_with_replacement(validUtf16Input.data(), + validUtf16Input.size()); + } else +#endif + { + return utf8_length_from_utf16le_with_replacement(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-8 @@ -6004,24 +5686,22 @@ utf8_length_from_utf16le_with_replacement( * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ -simdutf_warn_unused result utf8_length_from_utf16be_with_replacement( - const char16_t *input, size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -utf8_length_from_utf16be_with_replacement( - std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16_with_replacement< - endianness::BIG>(valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf8_length_from_utf16be_with_replacement(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf8_length_from_utf16be_with_replacement(const char16_t* input, size_t length) noexcept + -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_from_utf16be_with_replacement( + std::span validUtf16Input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16_with_replacement(validUtf16Input.data(), + validUtf16Input.size()); + } else +#endif + { + return utf8_length_from_utf16be_with_replacement(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6034,24 +5714,22 @@ utf8_length_from_utf16be_with_replacement( * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t. */ -simdutf_warn_unused size_t convert_latin1_to_utf16( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_latin1_to_utf16(const detail::input_span_of_byte_like auto &input, - std::span output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf16::convert( - input.data(), input.size(), output.data()); - } else - #endif - { +simdutf_warn_unused auto convert_latin1_to_utf16(const char* input, size_t length, char16_t* utf16Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf16( + const detail::input_span_of_byte_like auto& input, std::span output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf16::convert(input.data(), input.size(), output.data()); + } else +#endif + { return convert_latin1_to_utf16(reinterpret_cast(input.data()), input.size(), output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6067,25 +5745,23 @@ convert_latin1_to_utf16(const detail::input_span_of_byte_like auto &input, * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ -simdutf_warn_unused size_t convert_utf8_to_utf16le( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf8_to_utf16le(const detail::input_span_of_byte_like auto &utf8_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert( - utf8_input.data(), utf8_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf8_to_utf16le( - reinterpret_cast(utf8_input.data()), utf8_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_utf8_to_utf16le(const char* input, size_t length, char16_t* utf16Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16le( + const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert(utf8Input.data(), utf8Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf8_to_utf16le(reinterpret_cast(utf8Input.data()), utf8Input.size(), + utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16BE string. @@ -6099,26 +5775,22 @@ convert_utf8_to_utf16le(const detail::input_span_of_byte_like auto &utf8_input, * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ -simdutf_warn_unused size_t convert_utf8_to_utf16be( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf8_to_utf16be(const detail::input_span_of_byte_like auto &utf8_input, - std::span utf16_output) noexcept { - - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert( - utf8_input.data(), utf8_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf8_to_utf16be( - reinterpret_cast(utf8_input.data()), utf8_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_utf8_to_utf16be(const char* input, size_t length, char16_t* utf16Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16be( + const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert(utf8Input.data(), utf8Input.size(), utf16Output.data()); + } else +#endif + { + return convert_utf8_to_utf16be(reinterpret_cast(utf8Input.data()), utf8Input.size(), + utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -6138,26 +5810,23 @@ convert_utf8_to_utf16be(const detail::input_span_of_byte_like auto &utf8_input, * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused result convert_utf8_to_latin1_with_errors( - const char *input, size_t length, char *latin1_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf8_to_latin1_with_errors( - const detail::input_span_of_byte_like auto &utf8_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_latin1::convert_with_errors( - utf8_input.data(), utf8_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf8_to_latin1_with_errors( - reinterpret_cast(utf8_input.data()), utf8_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf8_to_latin1_with_errors(const char* input, size_t length, + char* latin1Output) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_latin1_with_errors( + const detail::input_span_of_byte_like auto& utf8Input, + detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_latin1::convert_with_errors(utf8Input.data(), utf8Input.size(), latin1Output.data()); + } else +#endif + { + return convert_utf8_to_latin1_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6176,26 +5845,23 @@ convert_utf8_to_latin1_with_errors( * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused result convert_utf8_to_utf16_with_errors( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf8_to_utf16_with_errors( - const detail::input_span_of_byte_like auto &utf8_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_with_errors( - utf8_input.data(), utf8_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf8_to_utf16_with_errors( - reinterpret_cast(utf8_input.data()), utf8_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_utf8_to_utf16_with_errors(const char* input, size_t length, + char16_t* utf16Output) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16_with_errors( + const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_with_errors(utf8Input.data(), utf8Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf8_to_utf16_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), + utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16LE string and stop on error. @@ -6211,26 +5877,23 @@ convert_utf8_to_utf16_with_errors( * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused result convert_utf8_to_utf16le_with_errors( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf8_to_utf16le_with_errors( - const detail::input_span_of_byte_like auto &utf8_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_with_errors( - utf8_input.data(), utf8_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf8_to_utf16le_with_errors( - reinterpret_cast(utf8_input.data()), utf8_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_utf8_to_utf16le_with_errors(const char* input, size_t length, + char16_t* utf16Output) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16le_with_errors( + const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_with_errors(utf8Input.data(), utf8Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf8_to_utf16le_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), + utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16BE string and stop on error. @@ -6246,26 +5909,23 @@ convert_utf8_to_utf16le_with_errors( * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused result convert_utf8_to_utf16be_with_errors( - const char *input, size_t length, char16_t *utf16_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf8_to_utf16be_with_errors( - const detail::input_span_of_byte_like auto &utf8_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_with_errors( - utf8_input.data(), utf8_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf8_to_utf16be_with_errors( - reinterpret_cast(utf8_input.data()), utf8_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_utf8_to_utf16be_with_errors(const char* input, size_t length, + char16_t* utf16Output) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16be_with_errors( + const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_with_errors(utf8Input.data(), utf8Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf8_to_utf16be_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), + utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -6281,25 +5941,22 @@ convert_utf8_to_utf16be_with_errors( * @return the number of written char32_t; 0 if the input was not valid UTF-8 * string */ -simdutf_warn_unused size_t convert_utf8_to_utf32( - const char *input, size_t length, char32_t *utf32_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf8_to_utf32(const detail::input_span_of_byte_like auto &utf8_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf32::convert(utf8_input.data(), utf8_input.size(), - utf32_output.data()); - } else - #endif - { - return convert_utf8_to_utf32( - reinterpret_cast(utf8_input.data()), utf8_input.size(), - utf32_output.data()); +simdutf_warn_unused auto convert_utf8_to_utf32(const char* input, size_t length, char32_t* utf32Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf32( + const detail::input_span_of_byte_like auto& utf8Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf32::convert(utf8Input.data(), utf8Input.size(), utf32Output.data()); + } else +#endif + { + return convert_utf8_to_utf32(reinterpret_cast(utf8Input.data()), utf8Input.size(), + utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-32 string and stop on error. @@ -6315,26 +5972,22 @@ convert_utf8_to_utf32(const detail::input_span_of_byte_like auto &utf8_input, * (in the input in code units) if any, or the number of char32_t written if * successful. */ -simdutf_warn_unused result convert_utf8_to_utf32_with_errors( - const char *input, size_t length, char32_t *utf32_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf8_to_utf32_with_errors( - const detail::input_span_of_byte_like auto &utf8_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf32::convert_with_errors( - utf8_input.data(), utf8_input.size(), utf32_output.data()); - } else - #endif - { - return convert_utf8_to_utf32_with_errors( - reinterpret_cast(utf8_input.data()), utf8_input.size(), - utf32_output.data()); +simdutf_warn_unused auto convert_utf8_to_utf32_with_errors(const char* input, size_t length, + char32_t* utf32Output) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf32_with_errors( + const detail::input_span_of_byte_like auto& utf8Input, std::span utf32Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf32::convert_with_errors(utf8Input.data(), utf8Input.size(), utf32Output.data()); + } else +#endif + { + return convert_utf8_to_utf32_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), + utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -6357,26 +6010,23 @@ convert_utf8_to_utf32_with_errors( * @param latin1_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if the input was not valid UTF-8 string */ -simdutf_warn_unused size_t convert_valid_utf8_to_latin1( - const char *input, size_t length, char *latin1_output) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf8_to_latin1( - const detail::input_span_of_byte_like auto &valid_utf8_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_latin1::convert_valid( - valid_utf8_input.data(), valid_utf8_input.size(), latin1_output.data()); - } else - #endif - { - return convert_valid_utf8_to_latin1( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size(), latin1_output.data()); +simdutf_warn_unused auto convert_valid_utf8_to_latin1(const char* input, size_t length, char* latin1Output) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_latin1( + const detail::input_span_of_byte_like auto& validUtf8Input, + detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_latin1::convert_valid(validUtf8Input.data(), validUtf8Input.size(), latin1Output.data()); + } else +#endif + { + return convert_valid_utf8_to_latin1(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size(), + latin1Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6390,26 +6040,23 @@ convert_valid_utf8_to_latin1( * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ -simdutf_warn_unused size_t convert_valid_utf8_to_utf16( - const char *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf8_to_utf16( - const detail::input_span_of_byte_like auto &valid_utf8_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_valid( - valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); - } else - #endif - { - return convert_valid_utf8_to_utf16( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size(), utf16_output.data()); +simdutf_warn_unused auto convert_valid_utf8_to_utf16(const char* input, size_t length, char16_t* utf16Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_utf16( + const detail::input_span_of_byte_like auto& validUtf8Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_valid(validUtf8Input.data(), validUtf8Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_valid_utf8_to_utf16(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size(), + utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-8 string into UTF-16LE string. @@ -6421,27 +6068,23 @@ convert_valid_utf8_to_utf16( * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ -simdutf_warn_unused size_t convert_valid_utf8_to_utf16le( - const char *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf8_to_utf16le( - const detail::input_span_of_byte_like auto &valid_utf8_input, - std::span utf16_output) noexcept { - - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_valid( - valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); - } else - #endif - { - return convert_valid_utf8_to_utf16le( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size(), utf16_output.data()); +simdutf_warn_unused auto convert_valid_utf8_to_utf16le(const char* input, size_t length, char16_t* utf16Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_utf16le( + const detail::input_span_of_byte_like auto& validUtf8Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_valid(validUtf8Input.data(), validUtf8Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_valid_utf8_to_utf16le(reinterpret_cast(validUtf8Input.data()), + validUtf8Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-8 string into UTF-16BE string. @@ -6453,26 +6096,23 @@ convert_valid_utf8_to_utf16le( * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ -simdutf_warn_unused size_t convert_valid_utf8_to_utf16be( - const char *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf8_to_utf16be( - const detail::input_span_of_byte_like auto &valid_utf8_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_valid( - valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); - } else - #endif - { - return convert_valid_utf8_to_utf16be( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size(), utf16_output.data()); +simdutf_warn_unused auto convert_valid_utf8_to_utf16be(const char* input, size_t length, char16_t* utf16Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_utf16be( + const detail::input_span_of_byte_like auto& validUtf8Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_valid(validUtf8Input.data(), validUtf8Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_valid_utf8_to_utf16be(reinterpret_cast(validUtf8Input.data()), + validUtf8Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -6486,26 +6126,22 @@ convert_valid_utf8_to_utf16be( * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t */ -simdutf_warn_unused size_t convert_valid_utf8_to_utf32( - const char *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf8_to_utf32( - const detail::input_span_of_byte_like auto &valid_utf8_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf32::convert_valid( - valid_utf8_input.data(), valid_utf8_input.size(), utf32_output.data()); - } else - #endif - { - return convert_valid_utf8_to_utf32( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size(), utf32_output.data()); +simdutf_warn_unused auto convert_valid_utf8_to_utf32(const char* input, size_t length, char32_t* utf32Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_utf32( + const detail::input_span_of_byte_like auto& validUtf8Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf32::convert_valid(validUtf8Input.data(), validUtf8Input.size(), utf32Output.data()); + } else +#endif + { + return convert_valid_utf8_to_utf32(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size(), + utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -6517,25 +6153,20 @@ convert_valid_utf8_to_utf32( * @param length the length of the string bytes * @return the number of bytes required to encode the Latin1 string as UTF-8 */ -simdutf_warn_unused size_t utf8_length_from_latin1(const char *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf8_length_from_latin1( - const detail::input_span_of_byte_like auto &latin1_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf8::utf8_length_from_latin1(latin1_input.data(), - latin1_input.size()); - } else - #endif - { - return utf8_length_from_latin1( - reinterpret_cast(latin1_input.data()), - latin1_input.size()); +simdutf_warn_unused auto utf8_length_from_latin1(const char* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_from_latin1( + const detail::input_span_of_byte_like auto& latin1Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf8::utf8_length_from_latin1(latin1Input.data(), latin1Input.size()); + } else +#endif + { + return utf8_length_from_latin1(reinterpret_cast(latin1Input.data()), latin1Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-8 string would require in Latin1 @@ -6550,25 +6181,20 @@ utf8_length_from_latin1( * @param length the length of the string in byte * @return the number of bytes required to encode the UTF-8 string as Latin1 */ -simdutf_warn_unused size_t latin1_length_from_utf8(const char *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -latin1_length_from_utf8( - const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::count_code_points(valid_utf8_input.data(), - valid_utf8_input.size()); - } else - #endif - { - return latin1_length_from_utf8( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size()); +simdutf_warn_unused auto latin1_length_from_utf8(const char* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto latin1_length_from_utf8( + const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::count_code_points(validUtf8Input.data(), validUtf8Input.size()); + } else +#endif + { + return latin1_length_from_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6586,25 +6212,20 @@ latin1_length_from_utf8( * @return the number of char16_t code units required to encode the UTF-8 string * as UTF-16LE */ -simdutf_warn_unused size_t utf16_length_from_utf8(const char *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf16_length_from_utf8( - const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::utf16_length_from_utf8(valid_utf8_input.data(), - valid_utf8_input.size()); - } else - #endif - { - return utf16_length_from_utf8( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size()); +simdutf_warn_unused auto utf16_length_from_utf8(const char* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf16_length_from_utf8( + const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::utf16_length_from_utf8(validUtf8Input.data(), validUtf8Input.size()); + } else +#endif + { + return utf16_length_from_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -6624,26 +6245,20 @@ utf16_length_from_utf8( * @return the number of char32_t code units required to encode the UTF-8 string * as UTF-32 */ -simdutf_warn_unused size_t utf32_length_from_utf8(const char *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf32_length_from_utf8( - const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { - - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::count_code_points(valid_utf8_input.data(), - valid_utf8_input.size()); - } else - #endif - { - return utf32_length_from_utf8( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size()); +simdutf_warn_unused auto utf32_length_from_utf8(const char* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf32_length_from_utf8( + const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::count_code_points(validUtf8Input.data(), validUtf8Input.size()); + } else +#endif + { + return utf32_length_from_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6662,26 +6277,22 @@ utf32_length_from_utf8( * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused size_t convert_utf16_to_utf8(const char16_t *input, - size_t length, - char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16_to_utf8( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16_to_utf8(utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf16_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf8( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert(utf16Input.data(), utf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_utf16_to_utf8(utf16Input.data(), utf16Input.size(), reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-16 string into UTF-8 @@ -6701,41 +6312,33 @@ convert_utf16_to_utf8( * @param utf8_len the maximum output length * @return the number of written char; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_utf16_to_utf8_safe(const char16_t *input, - size_t length, - char *utf8_output, - size_t utf8_len) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16_to_utf8_safe( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - // implementation note: outputspan is a forwarding ref to avoid copying - // and allow both lvalues and rvalues. std::span can be copied without - // problems, but std::vector should not, and this function should accept - // both. it will allow using an owning rvalue ref (example: passing a - // temporary std::string) as output, but the user will quickly find out - // that he has no way of getting the data out of the object in that case. - #if SIMDUTF_CPLUSPLUS23 - if consteval { - const full_result r = - scalar::utf16_to_utf8::convert_with_errors( - utf16_input.data(), utf16_input.size(), utf8_output.data(), - utf8_output.size()); - if (r.error != error_code::SUCCESS && - r.error != error_code::OUTPUT_BUFFER_TOO_SMALL) { - return 0; - } - return r.output_count; - } else - #endif - { - return convert_utf16_to_utf8_safe( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data()), utf8_output.size()); +simdutf_warn_unused auto convert_utf16_to_utf8_safe(const char16_t* input, size_t length, char* utf8Output, + size_t utf8Len) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf8_safe( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { + // implementation note: outputspan is a forwarding ref to avoid copying + // and allow both lvalues and rvalues. std::span can be copied without + // problems, but std::vector should not, and this function should accept + // both. it will allow using an owning rvalue ref (example: passing a + // temporary std::string) as output, but the user will quickly find out + // that he has no way of getting the data out of the object in that case. +#if SIMDUTF_CPLUSPLUS23 + if consteval { + const full_result r = scalar::utf16_to_utf8::convert_with_errors( + utf16Input.data(), utf16Input.size(), utf8Output.data(), utf8Output.size()); + if (r.error != error_code::SUCCESS && r.error != error_code::OUTPUT_BUFFER_TOO_SMALL) { + return 0; + } + return r.outputCount; + } else +#endif + { + return convert_utf16_to_utf8_safe(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data()), utf8Output.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -6754,26 +6357,23 @@ convert_utf16_to_utf8_safe( * @return number of written code units; 0 if input is not a valid UTF-16 string * or if it cannot be represented as Latin1 */ -simdutf_warn_unused size_t convert_utf16_to_latin1( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16_to_latin1( - std::span utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert( - utf16_input.data(), utf16_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf16_to_latin1( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf16_to_latin1(const char16_t* input, size_t length, char* latin1Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_latin1( + std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert(utf16Input.data(), utf16Input.size(), + latin1Output.data()); + } else +#endif + { + return convert_utf16_to_latin1(utf16Input.data(), utf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into Latin1 string. @@ -6791,26 +6391,23 @@ convert_utf16_to_latin1( * @return number of written code units; 0 if input is not a valid UTF-16LE * string or if it cannot be represented as Latin1 */ -simdutf_warn_unused size_t convert_utf16le_to_latin1( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16le_to_latin1( - std::span utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert( - utf16_input.data(), utf16_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf16le_to_latin1( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf16le_to_latin1(const char16_t* input, size_t length, char* latin1Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_latin1( + std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert(utf16Input.data(), utf16Input.size(), + latin1Output.data()); + } else +#endif + { + return convert_utf16le_to_latin1(utf16Input.data(), utf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into Latin1 string. @@ -6826,26 +6423,23 @@ convert_utf16le_to_latin1( * @return number of written code units; 0 if input is not a valid UTF-16BE * string or if it cannot be represented as Latin1 */ -simdutf_warn_unused size_t convert_utf16be_to_latin1( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16be_to_latin1( - std::span utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert( - utf16_input.data(), utf16_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf16be_to_latin1( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf16be_to_latin1(const char16_t* input, size_t length, char* latin1Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_latin1( + std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert(utf16Input.data(), utf16Input.size(), + latin1Output.data()); + } else +#endif + { + return convert_utf16be_to_latin1(utf16Input.data(), utf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6863,27 +6457,23 @@ convert_utf16be_to_latin1( * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused size_t convert_utf16le_to_utf8(const char16_t *input, - size_t length, - char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16le_to_utf8( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16le_to_utf8( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf16le_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf8( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert(utf16Input.data(), utf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_utf16le_to_utf8(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string. @@ -6899,27 +6489,22 @@ convert_utf16le_to_utf8( * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused size_t convert_utf16be_to_utf8(const char16_t *input, - size_t length, - char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16be_to_utf8( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16be_to_utf8( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf16be_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf8( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert(utf16Input.data(), utf16Input.size(), utf8Output.data()); + } else +#endif + { + return convert_utf16be_to_utf8(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -6939,26 +6524,23 @@ convert_utf16be_to_utf8( * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused result convert_utf16_to_latin1_with_errors( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16_to_latin1_with_errors( - std::span utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_with_errors( - utf16_input.data(), utf16_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf16_to_latin1_with_errors( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf16_to_latin1_with_errors(const char16_t* input, size_t length, + char* latin1Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_latin1_with_errors( + std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_with_errors(utf16Input.data(), utf16Input.size(), + latin1Output.data()); + } else +#endif + { + return convert_utf16_to_latin1_with_errors(utf16Input.data(), utf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into Latin1 string. @@ -6975,26 +6557,23 @@ convert_utf16_to_latin1_with_errors( * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused result convert_utf16le_to_latin1_with_errors( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16le_to_latin1_with_errors( - std::span utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_with_errors( - utf16_input.data(), utf16_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf16le_to_latin1_with_errors( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf16le_to_latin1_with_errors(const char16_t* input, size_t length, + char* latin1Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_latin1_with_errors( + std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_with_errors(utf16Input.data(), utf16Input.size(), + latin1Output.data()); + } else +#endif + { + return convert_utf16le_to_latin1_with_errors(utf16Input.data(), utf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into Latin1 string. @@ -7013,26 +6592,23 @@ convert_utf16le_to_latin1_with_errors( * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused result convert_utf16be_to_latin1_with_errors( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16be_to_latin1_with_errors( - std::span utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_with_errors( - utf16_input.data(), utf16_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf16be_to_latin1_with_errors( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf16be_to_latin1_with_errors(const char16_t* input, size_t length, + char* latin1Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_latin1_with_errors( + std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_with_errors(utf16Input.data(), utf16Input.size(), + latin1Output.data()); + } else +#endif + { + return convert_utf16be_to_latin1_with_errors(utf16Input.data(), utf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -7053,26 +6629,23 @@ convert_utf16be_to_latin1_with_errors( * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused result convert_utf16_to_utf8_with_errors( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16_to_utf8_with_errors( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_errors( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16_to_utf8_with_errors( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf16_to_utf8_with_errors(const char16_t* input, size_t length, + char* utf8Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf8_with_errors( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_errors(utf16Input.data(), utf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_utf16_to_utf8_with_errors(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-8 string and stop on error. @@ -7090,26 +6663,23 @@ convert_utf16_to_utf8_with_errors( * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused result convert_utf16le_to_utf8_with_errors( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16le_to_utf8_with_errors( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_errors( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16le_to_utf8_with_errors( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf16le_to_utf8_with_errors(const char16_t* input, size_t length, + char* utf8Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf8_with_errors( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_errors(utf16Input.data(), utf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_utf16le_to_utf8_with_errors(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string and stop on error. @@ -7127,26 +6697,23 @@ convert_utf16le_to_utf8_with_errors( * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused result convert_utf16be_to_utf8_with_errors( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16be_to_utf8_with_errors( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_errors( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16be_to_utf8_with_errors( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf16be_to_utf8_with_errors(const char16_t* input, size_t length, + char* utf8Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf8_with_errors( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_errors(utf16Input.data(), utf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_utf16be_to_utf8_with_errors(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-8 string, replacing @@ -7161,27 +6728,24 @@ convert_utf16be_to_utf8_with_errors( * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units - */ -simdutf_warn_unused size_t convert_utf16le_to_utf8_with_replacement( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16le_to_utf8_with_replacement( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_replacement( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16le_to_utf8_with_replacement( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); + */ +simdutf_warn_unused auto convert_utf16le_to_utf8_with_replacement(const char16_t* input, size_t length, + char* utf8Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf8_with_replacement( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_replacement(utf16Input.data(), utf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_utf16le_to_utf8_with_replacement(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string, replacing @@ -7197,26 +6761,23 @@ convert_utf16le_to_utf8_with_replacement( * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ -simdutf_warn_unused size_t convert_utf16be_to_utf8_with_replacement( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16be_to_utf8_with_replacement( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_replacement( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16be_to_utf8_with_replacement( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf16be_to_utf8_with_replacement(const char16_t* input, size_t length, + char* utf8Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf8_with_replacement( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_replacement(utf16Input.data(), utf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_utf16be_to_utf8_with_replacement(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16 string (native endianness) into UTF-8 string, @@ -7232,26 +6793,23 @@ convert_utf16be_to_utf8_with_replacement( * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ -simdutf_warn_unused size_t convert_utf16_to_utf8_with_replacement( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16_to_utf8_with_replacement( - std::span utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_replacement( - utf16_input.data(), utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf16_to_utf8_with_replacement( - utf16_input.data(), utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf16_to_utf8_with_replacement(const char16_t* input, size_t length, + char* utf8Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf8_with_replacement( + std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_replacement(utf16Input.data(), utf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_utf16_to_utf8_with_replacement(utf16Input.data(), utf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -7268,26 +6826,23 @@ convert_utf16_to_utf8_with_replacement( * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16_to_utf8( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf16_to_utf8( - std::span valid_utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_valid( - valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_valid_utf16_to_utf8( - valid_utf16_input.data(), valid_utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_valid_utf16_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16_to_utf8( + std::span validUtf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_valid(validUtf16Input.data(), validUtf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_valid_utf16_to_utf8(validUtf16Input.data(), validUtf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -7310,28 +6865,25 @@ convert_valid_utf16_to_utf8( * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16_to_latin1( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf16_to_latin1( - std::span valid_utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_valid_impl( - detail::constexpr_cast_ptr(valid_utf16_input.data()), - valid_utf16_input.size(), - detail::constexpr_cast_writeptr(latin1_output.data())); - } else - #endif - { - return convert_valid_utf16_to_latin1( - valid_utf16_input.data(), valid_utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_valid_utf16_to_latin1(const char16_t* input, size_t length, + char* latin1Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16_to_latin1( + std::span validUtf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept + -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_valid_impl( + detail::constexpr_cast_ptr(validUtf16Input.data()), validUtf16Input.size(), + detail::constexpr_cast_writeptr(latin1Output.data())); + } else +#endif + { + return convert_valid_utf16_to_latin1(validUtf16Input.data(), validUtf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-16LE string into Latin1 string. @@ -7352,28 +6904,25 @@ convert_valid_utf16_to_latin1( * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16le_to_latin1( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t -convert_valid_utf16le_to_latin1( - std::span valid_utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_valid_impl( - detail::constexpr_cast_ptr(valid_utf16_input.data()), - valid_utf16_input.size(), - detail::constexpr_cast_writeptr(latin1_output.data())); - } else - #endif - { - return convert_valid_utf16le_to_latin1( - valid_utf16_input.data(), valid_utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_valid_utf16le_to_latin1(const char16_t* input, size_t length, + char* latin1Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid_utf16le_to_latin1( + std::span validUtf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept + -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_valid_impl( + detail::constexpr_cast_ptr(validUtf16Input.data()), validUtf16Input.size(), + detail::constexpr_cast_writeptr(latin1Output.data())); + } else +#endif + { + return convert_valid_utf16le_to_latin1(validUtf16Input.data(), validUtf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into Latin1 string. @@ -7394,28 +6943,25 @@ convert_valid_utf16le_to_latin1( * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16be_to_latin1( - const char16_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t -convert_valid_utf16be_to_latin1( - std::span valid_utf16_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_valid_impl( - detail::constexpr_cast_ptr(valid_utf16_input.data()), - valid_utf16_input.size(), - detail::constexpr_cast_writeptr(latin1_output.data())); - } else - #endif - { - return convert_valid_utf16be_to_latin1( - valid_utf16_input.data(), valid_utf16_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_valid_utf16be_to_latin1(const char16_t* input, size_t length, + char* latin1Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid_utf16be_to_latin1( + std::span validUtf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept + -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_valid_impl( + detail::constexpr_cast_ptr(validUtf16Input.data()), validUtf16Input.size(), + detail::constexpr_cast_writeptr(latin1Output.data())); + } else +#endif + { + return convert_valid_utf16be_to_latin1(validUtf16Input.data(), validUtf16Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -7432,26 +6978,23 @@ convert_valid_utf16be_to_latin1( * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16le_to_utf8( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf16le_to_utf8( - std::span valid_utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_valid( - valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_valid_utf16le_to_utf8( - valid_utf16_input.data(), valid_utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_valid_utf16le_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16le_to_utf8( + std::span validUtf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_valid(validUtf16Input.data(), validUtf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_valid_utf16le_to_utf8(validUtf16Input.data(), validUtf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into UTF-8 string. @@ -7466,26 +7009,23 @@ convert_valid_utf16le_to_utf8( * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16be_to_utf8( - const char16_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf16be_to_utf8( - std::span valid_utf16_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_valid( - valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); - } else - #endif - { - return convert_valid_utf16be_to_utf8( - valid_utf16_input.data(), valid_utf16_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_valid_utf16be_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16be_to_utf8( + std::span validUtf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_valid(validUtf16Input.data(), validUtf16Input.size(), + utf8Output.data()); + } else +#endif + { + return convert_valid_utf16be_to_utf8(validUtf16Input.data(), validUtf16Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -7504,25 +7044,22 @@ convert_valid_utf16be_to_utf8( * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused size_t convert_utf16_to_utf32( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16_to_utf32(std::span utf16_input, - std::span utf32_output) noexcept { - - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert( - utf16_input.data(), utf16_input.size(), utf32_output.data()); - } else - #endif - { - return convert_utf16_to_utf32(utf16_input.data(), utf16_input.size(), - utf32_output.data()); +simdutf_warn_unused auto convert_utf16_to_utf32(const char16_t* input, size_t length, char32_t* utf32Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf32( + std::span utf16Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert(utf16Input.data(), utf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_utf16_to_utf32(utf16Input.data(), utf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-32 string. @@ -7538,24 +7075,22 @@ convert_utf16_to_utf32(std::span utf16_input, * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused size_t convert_utf16le_to_utf32( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16le_to_utf32(std::span utf16_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert( - utf16_input.data(), utf16_input.size(), utf32_output.data()); - } else - #endif - { - return convert_utf16le_to_utf32(utf16_input.data(), utf16_input.size(), - utf32_output.data()); +simdutf_warn_unused auto convert_utf16le_to_utf32(const char16_t* input, size_t length, char32_t* utf32Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf32( + std::span utf16Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert(utf16Input.data(), utf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_utf16le_to_utf32(utf16Input.data(), utf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-32 string. @@ -7571,24 +7106,22 @@ convert_utf16le_to_utf32(std::span utf16_input, * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused size_t convert_utf16be_to_utf32( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf16be_to_utf32(std::span utf16_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert( - utf16_input.data(), utf16_input.size(), utf32_output.data()); - } else - #endif - { - return convert_utf16be_to_utf32(utf16_input.data(), utf16_input.size(), - utf32_output.data()); +simdutf_warn_unused auto convert_utf16be_to_utf32(const char16_t* input, size_t length, char32_t* utf32Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf32( + std::span utf16Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert(utf16Input.data(), utf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_utf16be_to_utf32(utf16Input.data(), utf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-16 string into @@ -7607,24 +7140,22 @@ convert_utf16be_to_utf32(std::span utf16_input, * (in the input in code units) if any, or the number of char32_t written if * successful. */ -simdutf_warn_unused result convert_utf16_to_utf32_with_errors( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16_to_utf32_with_errors(std::span utf16_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_with_errors( - utf16_input.data(), utf16_input.size(), utf32_output.data()); - } else - #endif - { - return convert_utf16_to_utf32_with_errors( - utf16_input.data(), utf16_input.size(), utf32_output.data()); +simdutf_warn_unused auto convert_utf16_to_utf32_with_errors(const char16_t* input, size_t length, + char32_t* utf32Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf32_with_errors( + std::span utf16Input, std::span utf32Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_with_errors(utf16Input.data(), utf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_utf16_to_utf32_with_errors(utf16Input.data(), utf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-32 string and stop on error. @@ -7642,25 +7173,22 @@ convert_utf16_to_utf32_with_errors(std::span utf16_input, * (in the input in code units) if any, or the number of char32_t written if * successful. */ -simdutf_warn_unused result convert_utf16le_to_utf32_with_errors( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16le_to_utf32_with_errors( - std::span utf16_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_with_errors( - utf16_input.data(), utf16_input.size(), utf32_output.data()); - } else - #endif - { - return convert_utf16le_to_utf32_with_errors( - utf16_input.data(), utf16_input.size(), utf32_output.data()); +simdutf_warn_unused auto convert_utf16le_to_utf32_with_errors(const char16_t* input, size_t length, + char32_t* utf32Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf32_with_errors( + std::span utf16Input, std::span utf32Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_with_errors(utf16Input.data(), utf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_utf16le_to_utf32_with_errors(utf16Input.data(), utf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-32 string and stop on error. @@ -7678,25 +7206,22 @@ convert_utf16le_to_utf32_with_errors( * (in the input in code units) if any, or the number of char32_t written if * successful. */ -simdutf_warn_unused result convert_utf16be_to_utf32_with_errors( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf16be_to_utf32_with_errors( - std::span utf16_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_with_errors( - utf16_input.data(), utf16_input.size(), utf32_output.data()); - } else - #endif - { - return convert_utf16be_to_utf32_with_errors( - utf16_input.data(), utf16_input.size(), utf32_output.data()); +simdutf_warn_unused auto convert_utf16be_to_utf32_with_errors(const char16_t* input, size_t length, + char32_t* utf32Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf32_with_errors( + std::span utf16Input, std::span utf32Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_with_errors(utf16Input.data(), utf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_utf16be_to_utf32_with_errors(utf16Input.data(), utf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Using native endianness, convert valid UTF-16 string into UTF-32 string. @@ -7712,26 +7237,22 @@ convert_utf16be_to_utf32_with_errors( * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16_to_utf32( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf16_to_utf32(std::span valid_utf16_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_valid( - valid_utf16_input.data(), valid_utf16_input.size(), - utf32_output.data()); - } else - #endif - { - return convert_valid_utf16_to_utf32(valid_utf16_input.data(), - valid_utf16_input.size(), - utf32_output.data()); +simdutf_warn_unused auto convert_valid_utf16_to_utf32(const char16_t* input, size_t length, + char32_t* utf32Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16_to_utf32( + std::span validUtf16Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_valid(validUtf16Input.data(), validUtf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_valid_utf16_to_utf32(validUtf16Input.data(), validUtf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-16LE string into UTF-32 string. @@ -7746,26 +7267,22 @@ convert_valid_utf16_to_utf32(std::span valid_utf16_input, * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16le_to_utf32( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf16le_to_utf32(std::span valid_utf16_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_valid( - valid_utf16_input.data(), valid_utf16_input.size(), - utf32_output.data()); - } else - #endif - { - return convert_valid_utf16le_to_utf32(valid_utf16_input.data(), - valid_utf16_input.size(), - utf32_output.data()); +simdutf_warn_unused auto convert_valid_utf16le_to_utf32(const char16_t* input, size_t length, + char32_t* utf32Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16le_to_utf32( + std::span validUtf16Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_valid(validUtf16Input.data(), validUtf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_valid_utf16le_to_utf32(validUtf16Input.data(), validUtf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into UTF-32 string. @@ -7780,26 +7297,22 @@ convert_valid_utf16le_to_utf32(std::span valid_utf16_input, * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf16be_to_utf32( - const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf16be_to_utf32(std::span valid_utf16_input, - std::span utf32_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_valid( - valid_utf16_input.data(), valid_utf16_input.size(), - utf32_output.data()); - } else - #endif - { - return convert_valid_utf16be_to_utf32(valid_utf16_input.data(), - valid_utf16_input.size(), - utf32_output.data()); +simdutf_warn_unused auto convert_valid_utf16be_to_utf32(const char16_t* input, size_t length, + char32_t* utf32Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16be_to_utf32( + std::span validUtf16Input, std::span utf32Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_valid(validUtf16Input.data(), validUtf16Input.size(), + utf32Output.data()); + } else +#endif + { + return convert_valid_utf16be_to_utf32(validUtf16Input.data(), validUtf16Input.size(), utf32Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -7814,23 +7327,21 @@ convert_valid_utf16be_to_utf32(std::span valid_utf16_input, * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ -simdutf_warn_unused size_t utf8_length_from_utf16(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf8_length_from_utf16(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf8_length_from_utf16(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf8_length_from_utf16(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto utf8_length_from_utf16(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16(validUtf16Input.data(), + validUtf16Input.size()); + } else +#endif + { + return utf8_length_from_utf16(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Using native endianness; compute the number of bytes that this UTF-16 @@ -7850,24 +7361,22 @@ utf8_length_from_utf16(std::span valid_utf16_input) noexcept { * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ -simdutf_warn_unused result utf8_length_from_utf16_with_replacement( - const char16_t *input, size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -utf8_length_from_utf16_with_replacement( - std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16_with_replacement< - endianness::NATIVE>(valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf8_length_from_utf16_with_replacement(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf8_length_from_utf16_with_replacement(const char16_t* input, size_t length) noexcept + -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_from_utf16_with_replacement( + std::span validUtf16Input) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16_with_replacement(validUtf16Input.data(), + validUtf16Input.size()); + } else +#endif + { + return utf8_length_from_utf16_with_replacement(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-8 @@ -7880,23 +7389,21 @@ utf8_length_from_utf16_with_replacement( * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ -simdutf_warn_unused size_t utf8_length_from_utf16le(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t -utf8_length_from_utf16le(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf8_length_from_utf16le(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf8_length_from_utf16le(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 + simdutf_warn_unused auto utf8_length_from_utf16le(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16(validUtf16Input.data(), + validUtf16Input.size()); + } else +#endif + { + return utf8_length_from_utf16le(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-8 @@ -7909,23 +7416,20 @@ utf8_length_from_utf16le(std::span valid_utf16_input) noexcept { * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-8 */ -simdutf_warn_unused size_t utf8_length_from_utf16be(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf8_length_from_utf16be(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf8_length_from_utf16be(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf8_length_from_utf16be(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto utf8_length_from_utf16be(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16(validUtf16Input.data(), validUtf16Input.size()); + } else +#endif + { + return utf8_length_from_utf16be(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -7942,26 +7446,21 @@ utf8_length_from_utf16be(std::span valid_utf16_input) noexcept { * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ -simdutf_warn_unused size_t convert_utf32_to_utf8(const char32_t *input, - size_t length, - char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf32_to_utf8( - std::span utf32_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf8::convert( - utf32_input.data(), utf32_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf32_to_utf8(utf32_input.data(), utf32_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf32_to_utf8(const char32_t* input, size_t length, char* utf8Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf8( + std::span utf32Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf8::convert(utf32Input.data(), utf32Input.size(), utf8Output.data()); + } else +#endif + { + return convert_utf32_to_utf8(utf32Input.data(), utf32Input.size(), reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-8 string and stop on error. @@ -7979,26 +7478,22 @@ convert_utf32_to_utf8( * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused result convert_utf32_to_utf8_with_errors( - const char32_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf32_to_utf8_with_errors( - std::span utf32_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf8::convert_with_errors( - utf32_input.data(), utf32_input.size(), utf8_output.data()); - } else - #endif - { - return convert_utf32_to_utf8_with_errors( - utf32_input.data(), utf32_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_utf32_to_utf8_with_errors(const char32_t* input, size_t length, + char* utf8Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf8_with_errors( + std::span utf32Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf8::convert_with_errors(utf32Input.data(), utf32Input.size(), utf8Output.data()); + } else +#endif + { + return convert_utf32_to_utf8_with_errors(utf32Input.data(), utf32Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-8 string. @@ -8013,26 +7508,22 @@ convert_utf32_to_utf8_with_errors( * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf32_to_utf8( - const char32_t *input, size_t length, char *utf8_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf32_to_utf8( - std::span valid_utf32_input, - detail::output_span_of_byte_like auto &&utf8_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf8::convert_valid( - valid_utf32_input.data(), valid_utf32_input.size(), utf8_output.data()); - } else - #endif - { - return convert_valid_utf32_to_utf8( - valid_utf32_input.data(), valid_utf32_input.size(), - reinterpret_cast(utf8_output.data())); +simdutf_warn_unused auto convert_valid_utf32_to_utf8(const char32_t* input, size_t length, char* utf8Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf32_to_utf8( + std::span validUtf32Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf8::convert_valid(validUtf32Input.data(), validUtf32Input.size(), utf8Output.data()); + } else +#endif + { + return convert_valid_utf32_to_utf8(validUtf32Input.data(), validUtf32Input.size(), + reinterpret_cast(utf8Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -8050,24 +7541,22 @@ convert_valid_utf32_to_utf8( * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ -simdutf_warn_unused size_t convert_utf32_to_utf16( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf32_to_utf16(std::span utf32_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert( - utf32_input.data(), utf32_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf32_to_utf16(utf32_input.data(), utf32_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_utf32_to_utf16(const char32_t* input, size_t length, char16_t* utf16Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16( + std::span utf32Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert(utf32Input.data(), utf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf32_to_utf16(utf32Input.data(), utf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16LE string. @@ -8082,24 +7571,22 @@ convert_utf32_to_utf16(std::span utf32_input, * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ -simdutf_warn_unused size_t convert_utf32_to_utf16le( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf32_to_utf16le(std::span utf32_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert( - utf32_input.data(), utf32_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf32_to_utf16le(utf32_input.data(), utf32_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_utf32_to_utf16le(const char32_t* input, size_t length, char16_t* utf16Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16le( + std::span utf32Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert(utf32Input.data(), utf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf32_to_utf16le(utf32Input.data(), utf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -8117,26 +7604,22 @@ convert_utf32_to_utf16le(std::span utf32_input, * @return number of written code units; 0 if input is not a valid UTF-32 string * or if it cannot be represented as Latin1 */ -simdutf_warn_unused size_t convert_utf32_to_latin1( - const char32_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf32_to_latin1( - std::span utf32_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_latin1::convert( - utf32_input.data(), utf32_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf32_to_latin1( - utf32_input.data(), utf32_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf32_to_latin1(const char32_t* input, size_t length, char* latin1Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_latin1( + std::span utf32Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_latin1::convert(utf32Input.data(), utf32Input.size(), latin1Output.data()); + } else +#endif + { + return convert_utf32_to_latin1(utf32Input.data(), utf32Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into Latin1 string and stop on error. @@ -8155,26 +7638,22 @@ convert_utf32_to_latin1( * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused result convert_utf32_to_latin1_with_errors( - const char32_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf32_to_latin1_with_errors( - std::span utf32_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_latin1::convert_with_errors( - utf32_input.data(), utf32_input.size(), latin1_output.data()); - } else - #endif - { - return convert_utf32_to_latin1_with_errors( - utf32_input.data(), utf32_input.size(), - reinterpret_cast(latin1_output.data())); +simdutf_warn_unused auto convert_utf32_to_latin1_with_errors(const char32_t* input, size_t length, + char* latin1Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_latin1_with_errors( + std::span utf32Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_latin1::convert_with_errors(utf32Input.data(), utf32Input.size(), latin1Output.data()); + } else +#endif + { + return convert_utf32_to_latin1_with_errors(utf32Input.data(), utf32Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into Latin1 string. @@ -8196,28 +7675,25 @@ convert_utf32_to_latin1_with_errors( * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf32_to_latin1( - const char32_t *input, size_t length, char *latin1_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t -convert_valid_utf32_to_latin1( - std::span valid_utf32_input, - detail::output_span_of_byte_like auto &&latin1_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_latin1::convert_valid( - detail::constexpr_cast_ptr(valid_utf32_input.data()), - valid_utf32_input.size(), - detail::constexpr_cast_writeptr(latin1_output.data())); - } - #endif +simdutf_warn_unused auto convert_valid_utf32_to_latin1(const char32_t* input, size_t length, + char* latin1Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid_utf32_to_latin1( + std::span validUtf32Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept + -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_latin1::convert_valid(detail::constexpr_cast_ptr(validUtf32Input.data()), + validUtf32Input.size(), + detail::constexpr_cast_writeptr(latin1Output.data())); + } +#endif { - return convert_valid_utf32_to_latin1( - valid_utf32_input.data(), valid_utf32_input.size(), - reinterpret_cast(latin1_output.data())); + return convert_valid_utf32_to_latin1(validUtf32Input.data(), validUtf32Input.size(), + reinterpret_cast(latin1Output.data())); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-32 string would require in Latin1 @@ -8231,9 +7707,9 @@ convert_valid_utf32_to_latin1( * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t -latin1_length_from_utf32(size_t length) noexcept { - return length; +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto latin1_length_from_utf32(size_t length) noexcept + -> size_t { + return length; } /** @@ -8244,9 +7720,9 @@ latin1_length_from_utf32(size_t length) noexcept { * @return the length of the string in 4-byte code units (char32_t) required to * encode the Latin1 string as UTF-32 */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t -utf32_length_from_latin1(size_t length) noexcept { - return length; +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto utf32_length_from_latin1(size_t length) noexcept + -> size_t { + return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -8264,24 +7740,22 @@ utf32_length_from_latin1(size_t length) noexcept { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ -simdutf_warn_unused size_t convert_utf32_to_utf16be( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_utf32_to_utf16be(std::span utf32_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert( - utf32_input.data(), utf32_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf32_to_utf16be(utf32_input.data(), utf32_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_utf32_to_utf16be(const char32_t* input, size_t length, char16_t* utf16Buffer) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16be( + std::span utf32Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert(utf32Input.data(), utf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf32_to_utf16be(utf32Input.data(), utf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-32 string into UTF-16 @@ -8300,24 +7774,22 @@ convert_utf32_to_utf16be(std::span utf32_input, * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused result convert_utf32_to_utf16_with_errors( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf32_to_utf16_with_errors(std::span utf32_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_with_errors( - utf32_input.data(), utf32_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf32_to_utf16_with_errors( - utf32_input.data(), utf32_input.size(), utf16_output.data()); +simdutf_warn_unused auto convert_utf32_to_utf16_with_errors(const char32_t* input, size_t length, + char16_t* utf16Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16_with_errors( + std::span utf32Input, std::span utf16Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_with_errors(utf32Input.data(), utf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf32_to_utf16_with_errors(utf32Input.data(), utf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16LE string and stop on error. @@ -8335,25 +7807,22 @@ convert_utf32_to_utf16_with_errors(std::span utf32_input, * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused result convert_utf32_to_utf16le_with_errors( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf32_to_utf16le_with_errors( - std::span utf32_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_with_errors( - utf32_input.data(), utf32_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf32_to_utf16le_with_errors( - utf32_input.data(), utf32_input.size(), utf16_output.data()); +simdutf_warn_unused auto convert_utf32_to_utf16le_with_errors(const char32_t* input, size_t length, + char16_t* utf16Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16le_with_errors( + std::span utf32Input, std::span utf16Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_with_errors(utf32Input.data(), utf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf32_to_utf16le_with_errors(utf32Input.data(), utf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16BE string and stop on error. @@ -8371,25 +7840,22 @@ convert_utf32_to_utf16le_with_errors( * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused result convert_utf32_to_utf16be_with_errors( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -convert_utf32_to_utf16be_with_errors( - std::span utf32_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_with_errors( - utf32_input.data(), utf32_input.size(), utf16_output.data()); - } else - #endif - { - return convert_utf32_to_utf16be_with_errors( - utf32_input.data(), utf32_input.size(), utf16_output.data()); +simdutf_warn_unused auto convert_utf32_to_utf16be_with_errors(const char32_t* input, size_t length, + char16_t* utf16Buffer) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16be_with_errors( + std::span utf32Input, std::span utf16Output) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_with_errors(utf32Input.data(), utf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_utf32_to_utf16be_with_errors(utf32Input.data(), utf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Using native endianness, convert valid UTF-32 string into a UTF-16 string. @@ -8404,27 +7870,22 @@ convert_utf32_to_utf16be_with_errors( * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf32_to_utf16( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf32_to_utf16(std::span valid_utf32_input, - std::span utf16_output) noexcept { - - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_valid( - valid_utf32_input.data(), valid_utf32_input.size(), - utf16_output.data()); - } else - #endif - { - return convert_valid_utf32_to_utf16(valid_utf32_input.data(), - valid_utf32_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_valid_utf32_to_utf16(const char32_t* input, size_t length, + char16_t* utf16Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf32_to_utf16( + std::span validUtf32Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_valid(validUtf32Input.data(), validUtf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_valid_utf32_to_utf16(validUtf32Input.data(), validUtf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-16LE string. @@ -8439,26 +7900,22 @@ convert_valid_utf32_to_utf16(std::span valid_utf32_input, * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf32_to_utf16le( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf32_to_utf16le(std::span valid_utf32_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_valid( - valid_utf32_input.data(), valid_utf32_input.size(), - utf16_output.data()); - } else - #endif - { - return convert_valid_utf32_to_utf16le(valid_utf32_input.data(), - valid_utf32_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_valid_utf32_to_utf16le(const char32_t* input, size_t length, + char16_t* utf16Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf32_to_utf16le( + std::span validUtf32Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_valid(validUtf32Input.data(), validUtf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_valid_utf32_to_utf16le(validUtf32Input.data(), validUtf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-16BE string. @@ -8473,26 +7930,22 @@ convert_valid_utf32_to_utf16le(std::span valid_utf32_input, * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused size_t convert_valid_utf32_to_utf16be( - const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -convert_valid_utf32_to_utf16be(std::span valid_utf32_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_valid( - valid_utf32_input.data(), valid_utf32_input.size(), - utf16_output.data()); - } else - #endif - { - return convert_valid_utf32_to_utf16be(valid_utf32_input.data(), - valid_utf32_input.size(), - utf16_output.data()); +simdutf_warn_unused auto convert_valid_utf32_to_utf16be(const char32_t* input, size_t length, + char16_t* utf16Buffer) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf32_to_utf16be( + std::span validUtf32Input, std::span utf16Output) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_valid(validUtf32Input.data(), validUtf32Input.size(), + utf16Output.data()); + } else +#endif + { + return convert_valid_utf32_to_utf16be(validUtf32Input.data(), validUtf32Input.size(), utf16Output.data()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 @@ -8512,21 +7965,20 @@ convert_valid_utf32_to_utf16be(std::span valid_utf32_input, void change_endianness_utf16(const char16_t *input, size_t length, char16_t *output) noexcept; #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 void -change_endianness_utf16(std::span utf16_input, - std::span utf16_output) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::change_endianness_utf16( - utf16_input.data(), utf16_input.size(), utf16_output.data()); - } else - #endif - { - return change_endianness_utf16(utf16_input.data(), utf16_input.size(), - utf16_output.data()); +simdutf_really_inline simdutf_constexpr23 void change_endianness_utf16(std::span utf16Input, + std::span utf16Output) noexcept { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + scalar::utf16::change_endianness_utf16(utf16Input.data(), utf16Input.size(), utf16Output.data()); + return; + } else +#endif + { + change_endianness_utf16(utf16Input.data(), utf16Input.size(), utf16Output.data()); + return; } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -8541,23 +7993,20 @@ change_endianness_utf16(std::span utf16_input, * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-8 */ -simdutf_warn_unused size_t utf8_length_from_utf32(const char32_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf8_length_from_utf32(std::span valid_utf32_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32::utf8_length_from_utf32(valid_utf32_input.data(), - valid_utf32_input.size()); - } else - #endif - { - return utf8_length_from_utf32(valid_utf32_input.data(), - valid_utf32_input.size()); +simdutf_warn_unused auto utf8_length_from_utf32(const char32_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto utf8_length_from_utf32(std::span validUtf32Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32::utf8_length_from_utf32(validUtf32Input.data(), validUtf32Input.size()); + } else +#endif + { + return utf8_length_from_utf32(validUtf32Input.data(), validUtf32Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -8572,23 +8021,20 @@ utf8_length_from_utf32(std::span valid_utf32_input) noexcept { * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-16 */ -simdutf_warn_unused size_t utf16_length_from_utf32(const char32_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf16_length_from_utf32(std::span valid_utf32_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32::utf16_length_from_utf32(valid_utf32_input.data(), - valid_utf32_input.size()); - } else - #endif - { - return utf16_length_from_utf32(valid_utf32_input.data(), - valid_utf32_input.size()); +simdutf_warn_unused auto utf16_length_from_utf32(const char32_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto utf16_length_from_utf32(std::span validUtf32Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32::utf16_length_from_utf32(validUtf32Input.data(), validUtf32Input.size()); + } else +#endif + { + return utf16_length_from_utf32(validUtf32Input.data(), validUtf32Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Using native endianness; Compute the number of bytes that this UTF-16 @@ -8605,23 +8051,21 @@ utf16_length_from_utf32(std::span valid_utf32_input) noexcept { * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-32 */ -simdutf_warn_unused size_t utf32_length_from_utf16(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf32_length_from_utf16(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf32_length_from_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf32_length_from_utf16(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf32_length_from_utf16(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto utf32_length_from_utf16(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf32_length_from_utf16(validUtf16Input.data(), + validUtf16Input.size()); + } else +#endif + { + return utf32_length_from_utf16(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-32 @@ -8638,24 +8082,21 @@ utf32_length_from_utf16(std::span valid_utf16_input) noexcept { * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-32 */ -simdutf_warn_unused size_t utf32_length_from_utf16le(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf32_length_from_utf16le( - std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf32_length_from_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf32_length_from_utf16le(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf32_length_from_utf16le(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto utf32_length_from_utf16le(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf32_length_from_utf16(validUtf16Input.data(), + validUtf16Input.size()); + } else +#endif + { + return utf32_length_from_utf16le(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-32 @@ -8672,24 +8113,20 @@ utf32_length_from_utf16le( * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-32 */ -simdutf_warn_unused size_t utf32_length_from_utf16be(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -utf32_length_from_utf16be( - std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf32_length_from_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return utf32_length_from_utf16be(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto utf32_length_from_utf16be(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto utf32_length_from_utf16be(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf32_length_from_utf16(validUtf16Input.data(), validUtf16Input.size()); + } else +#endif + { + return utf32_length_from_utf16be(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 @@ -8707,22 +8144,20 @@ utf32_length_from_utf16be( * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ -simdutf_warn_unused size_t count_utf16(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -count_utf16(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::count_code_points( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return count_utf16(valid_utf16_input.data(), valid_utf16_input.size()); +simdutf_warn_unused auto count_utf16(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto count_utf16(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::count_code_points(validUtf16Input.data(), validUtf16Input.size()); + } else +#endif + { + return count_utf16(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Count the number of code points (characters) in the string assuming that @@ -8738,22 +8173,20 @@ count_utf16(std::span valid_utf16_input) noexcept { * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ -simdutf_warn_unused size_t count_utf16le(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -count_utf16le(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::count_code_points( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return count_utf16le(valid_utf16_input.data(), valid_utf16_input.size()); +simdutf_warn_unused auto count_utf16le(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto count_utf16le(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::count_code_points(validUtf16Input.data(), validUtf16Input.size()); + } else +#endif + { + return count_utf16le(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Count the number of code points (characters) in the string assuming that @@ -8769,22 +8202,20 @@ count_utf16le(std::span valid_utf16_input) noexcept { * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ -simdutf_warn_unused size_t count_utf16be(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -count_utf16be(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::count_code_points( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return count_utf16be(valid_utf16_input.data(), valid_utf16_input.size()); +simdutf_warn_unused auto count_utf16be(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto count_utf16be(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::count_code_points(validUtf16Input.data(), validUtf16Input.size()); + } else +#endif + { + return count_utf16be(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 @@ -8800,23 +8231,20 @@ count_utf16be(std::span valid_utf16_input) noexcept { * @param length the length of the string in bytes * @return number of code points */ -simdutf_warn_unused size_t count_utf8(const char *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf8( - const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::count_code_points(valid_utf8_input.data(), - valid_utf8_input.size()); - } else - #endif - { - return count_utf8(reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size()); +simdutf_warn_unused auto count_utf8(const char* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto count_utf8(const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::count_code_points(validUtf8Input.data(), validUtf8Input.size()); + } else +#endif + { + return count_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Given a valid UTF-8 string having a possibly truncated last character, @@ -8832,24 +8260,20 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf8( * @param length the length of the string in bytes * @return the length of the string in bytes, possibly shorter by 1 to 3 bytes */ -simdutf_warn_unused size_t trim_partial_utf8(const char *input, size_t length); - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -trim_partial_utf8( - const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::trim_partial_utf8(valid_utf8_input.data(), - valid_utf8_input.size()); - } else - #endif - { - return trim_partial_utf8( - reinterpret_cast(valid_utf8_input.data()), - valid_utf8_input.size()); +simdutf_warn_unused auto trim_partial_utf8(const char* input, size_t length) -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto trim_partial_utf8( + const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::trim_partial_utf8(validUtf8Input.data(), validUtf8Input.size()); + } else +#endif + { + return trim_partial_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_UTF16 @@ -8867,23 +8291,20 @@ trim_partial_utf8( * @param length the length of the string in bytes * @return the length of the string in bytes, possibly shorter by 1 unit */ -simdutf_warn_unused size_t trim_partial_utf16be(const char16_t *input, - size_t length); - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -trim_partial_utf16be(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::trim_partial_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return trim_partial_utf16be(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto trim_partial_utf16be(const char16_t* input, size_t length) -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto trim_partial_utf16be(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::trim_partial_utf16(validUtf16Input.data(), validUtf16Input.size()); + } else +#endif + { + return trim_partial_utf16be(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Given a valid UTF-16LE string having a possibly truncated last character, @@ -8899,23 +8320,20 @@ trim_partial_utf16be(std::span valid_utf16_input) noexcept { * @param length the length of the string in bytes * @return the length of the string in unit, possibly shorter by 1 unit */ -simdutf_warn_unused size_t trim_partial_utf16le(const char16_t *input, - size_t length); - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -trim_partial_utf16le(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::trim_partial_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return trim_partial_utf16le(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto trim_partial_utf16le(const char16_t* input, size_t length) -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto trim_partial_utf16le(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::trim_partial_utf16(validUtf16Input.data(), validUtf16Input.size()); + } else +#endif + { + return trim_partial_utf16le(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Given a valid UTF-16 string having a possibly truncated last character, @@ -8931,23 +8349,20 @@ trim_partial_utf16le(std::span valid_utf16_input) noexcept { * @param length the length of the string in bytes * @return the length of the string in unit, possibly shorter by 1 unit */ -simdutf_warn_unused size_t trim_partial_utf16(const char16_t *input, - size_t length); - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -trim_partial_utf16(std::span valid_utf16_input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::trim_partial_utf16( - valid_utf16_input.data(), valid_utf16_input.size()); - } else - #endif - { - return trim_partial_utf16(valid_utf16_input.data(), - valid_utf16_input.size()); +simdutf_warn_unused auto trim_partial_utf16(const char16_t* input, size_t length) -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto trim_partial_utf16(std::span validUtf16Input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::trim_partial_utf16(validUtf16Input.data(), validUtf16Input.size()); + } else +#endif + { + return trim_partial_utf16(validUtf16Input.data(), validUtf16Input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_BASE64 || SIMDUTF_FEATURE_UTF16 || \ @@ -8963,16 +8378,12 @@ trim_partial_utf16(std::span valid_utf16_input) noexcept { // ASCII spaces are ' ', '\t', '\n', '\r', '\f' // garbage characters are characters that are not part of the base64 alphabet // nor ASCII spaces. -constexpr uint64_t base64_reverse_padding = - 2; /* modifier for base64_default and base64_url */ +constexpr uint64_t base64ReversePadding = 2; /* modifier for base64_default and base64_url */ enum base64_options : uint64_t { base64_default = 0, /* standard base64 format (with padding) */ base64_url = 1, /* base64url format (no padding) */ - base64_default_no_padding = - base64_default | - base64_reverse_padding, /* standard base64 format without padding */ - base64_url_with_padding = - base64_url | base64_reverse_padding, /* base64url with padding */ + base64_default_no_padding = base64_default | base64ReversePadding, /* standard base64 format without padding */ + base64_url_with_padding = base64_url | base64ReversePadding, /* base64url with padding */ base64_default_accept_garbage = 4, /* standard base64 format accepting garbage characters, the input stops with the first '=' if any */ @@ -9000,16 +8411,14 @@ enum last_chunk_handling_options : uint64_t { 3 /* only decode full blocks (4 base64 characters, no padding) */ }; -inline simdutf_constexpr23 bool -is_partial(last_chunk_handling_options options) { - return (options == stop_before_partial) || (options == only_full_chunks); +simdutf_constexpr23 auto is_partial(last_chunk_handling_options options) -> bool { + return (options == stop_before_partial) || (options == only_full_chunks); } namespace detail { -simdutf_warn_unused const char *find(const char *start, const char *end, - char character) noexcept; -simdutf_warn_unused const char16_t * -find(const char16_t *start, const char16_t *end, char16_t character) noexcept; +simdutf_warn_unused auto find(const char* start, const char* end, char character) noexcept -> const char*; +simdutf_warn_unused auto find(const char16_t* start, const char16_t* end, char16_t character) noexcept -> const + char16_t*; } // namespace detail /** @@ -9022,29 +8431,34 @@ find(const char16_t *start, const char16_t *end, char16_t character) noexcept; * or a pointer to the end of the string if the character is not found. * */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char * -find(const char *start, const char *end, char character) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - for (; start != end; ++start) - if (*start == character) - return start; - return end; - } else - #endif - { +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto find(const char* start, const char* end, + char character) noexcept -> const char* { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + for (; start != end; ++start) { + if (*start == character) { + return start; + } + } + return end; + } else +#endif + { return detail::find(start, end, character); } } -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char16_t * -find(const char16_t *start, const char16_t *end, char16_t character) noexcept { +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto find(const char16_t* start, const char16_t* end, + char16_t character) noexcept -> const + char16_t* { // implementation note: this is repeated instead of a template, to ensure // the api is still a function and compiles without concepts #if SIMDUTF_CPLUSPLUS23 if consteval { - for (; start != end; ++start) - if (*start == character) - return start; + for (; start != end; ++start) { + if (*start == character) { + return start; + } + } return end; } else #endif @@ -9061,8 +8475,8 @@ find(const char16_t *start, const char16_t *end, char16_t character) noexcept { namespace simdutf { namespace { -namespace tables { -namespace base64 { + +namespace tables::base64 { namespace base64_default { constexpr char e0[256] = { @@ -9724,220 +9138,143 @@ constexpr uint32_t d3[256] = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; } // namespace base64_default_or_url -constexpr uint64_t thintable_epi8[256] = { - 0x0706050403020100, 0x0007060504030201, 0x0007060504030200, - 0x0000070605040302, 0x0007060504030100, 0x0000070605040301, - 0x0000070605040300, 0x0000000706050403, 0x0007060504020100, - 0x0000070605040201, 0x0000070605040200, 0x0000000706050402, - 0x0000070605040100, 0x0000000706050401, 0x0000000706050400, - 0x0000000007060504, 0x0007060503020100, 0x0000070605030201, - 0x0000070605030200, 0x0000000706050302, 0x0000070605030100, - 0x0000000706050301, 0x0000000706050300, 0x0000000007060503, - 0x0000070605020100, 0x0000000706050201, 0x0000000706050200, - 0x0000000007060502, 0x0000000706050100, 0x0000000007060501, - 0x0000000007060500, 0x0000000000070605, 0x0007060403020100, - 0x0000070604030201, 0x0000070604030200, 0x0000000706040302, - 0x0000070604030100, 0x0000000706040301, 0x0000000706040300, - 0x0000000007060403, 0x0000070604020100, 0x0000000706040201, - 0x0000000706040200, 0x0000000007060402, 0x0000000706040100, - 0x0000000007060401, 0x0000000007060400, 0x0000000000070604, - 0x0000070603020100, 0x0000000706030201, 0x0000000706030200, - 0x0000000007060302, 0x0000000706030100, 0x0000000007060301, - 0x0000000007060300, 0x0000000000070603, 0x0000000706020100, - 0x0000000007060201, 0x0000000007060200, 0x0000000000070602, - 0x0000000007060100, 0x0000000000070601, 0x0000000000070600, - 0x0000000000000706, 0x0007050403020100, 0x0000070504030201, - 0x0000070504030200, 0x0000000705040302, 0x0000070504030100, - 0x0000000705040301, 0x0000000705040300, 0x0000000007050403, - 0x0000070504020100, 0x0000000705040201, 0x0000000705040200, - 0x0000000007050402, 0x0000000705040100, 0x0000000007050401, - 0x0000000007050400, 0x0000000000070504, 0x0000070503020100, - 0x0000000705030201, 0x0000000705030200, 0x0000000007050302, - 0x0000000705030100, 0x0000000007050301, 0x0000000007050300, - 0x0000000000070503, 0x0000000705020100, 0x0000000007050201, - 0x0000000007050200, 0x0000000000070502, 0x0000000007050100, - 0x0000000000070501, 0x0000000000070500, 0x0000000000000705, - 0x0000070403020100, 0x0000000704030201, 0x0000000704030200, - 0x0000000007040302, 0x0000000704030100, 0x0000000007040301, - 0x0000000007040300, 0x0000000000070403, 0x0000000704020100, - 0x0000000007040201, 0x0000000007040200, 0x0000000000070402, - 0x0000000007040100, 0x0000000000070401, 0x0000000000070400, - 0x0000000000000704, 0x0000000703020100, 0x0000000007030201, - 0x0000000007030200, 0x0000000000070302, 0x0000000007030100, - 0x0000000000070301, 0x0000000000070300, 0x0000000000000703, - 0x0000000007020100, 0x0000000000070201, 0x0000000000070200, - 0x0000000000000702, 0x0000000000070100, 0x0000000000000701, - 0x0000000000000700, 0x0000000000000007, 0x0006050403020100, - 0x0000060504030201, 0x0000060504030200, 0x0000000605040302, - 0x0000060504030100, 0x0000000605040301, 0x0000000605040300, - 0x0000000006050403, 0x0000060504020100, 0x0000000605040201, - 0x0000000605040200, 0x0000000006050402, 0x0000000605040100, - 0x0000000006050401, 0x0000000006050400, 0x0000000000060504, - 0x0000060503020100, 0x0000000605030201, 0x0000000605030200, - 0x0000000006050302, 0x0000000605030100, 0x0000000006050301, - 0x0000000006050300, 0x0000000000060503, 0x0000000605020100, - 0x0000000006050201, 0x0000000006050200, 0x0000000000060502, - 0x0000000006050100, 0x0000000000060501, 0x0000000000060500, - 0x0000000000000605, 0x0000060403020100, 0x0000000604030201, - 0x0000000604030200, 0x0000000006040302, 0x0000000604030100, - 0x0000000006040301, 0x0000000006040300, 0x0000000000060403, - 0x0000000604020100, 0x0000000006040201, 0x0000000006040200, - 0x0000000000060402, 0x0000000006040100, 0x0000000000060401, - 0x0000000000060400, 0x0000000000000604, 0x0000000603020100, - 0x0000000006030201, 0x0000000006030200, 0x0000000000060302, - 0x0000000006030100, 0x0000000000060301, 0x0000000000060300, - 0x0000000000000603, 0x0000000006020100, 0x0000000000060201, - 0x0000000000060200, 0x0000000000000602, 0x0000000000060100, - 0x0000000000000601, 0x0000000000000600, 0x0000000000000006, - 0x0000050403020100, 0x0000000504030201, 0x0000000504030200, - 0x0000000005040302, 0x0000000504030100, 0x0000000005040301, - 0x0000000005040300, 0x0000000000050403, 0x0000000504020100, - 0x0000000005040201, 0x0000000005040200, 0x0000000000050402, - 0x0000000005040100, 0x0000000000050401, 0x0000000000050400, - 0x0000000000000504, 0x0000000503020100, 0x0000000005030201, - 0x0000000005030200, 0x0000000000050302, 0x0000000005030100, - 0x0000000000050301, 0x0000000000050300, 0x0000000000000503, - 0x0000000005020100, 0x0000000000050201, 0x0000000000050200, - 0x0000000000000502, 0x0000000000050100, 0x0000000000000501, - 0x0000000000000500, 0x0000000000000005, 0x0000000403020100, - 0x0000000004030201, 0x0000000004030200, 0x0000000000040302, - 0x0000000004030100, 0x0000000000040301, 0x0000000000040300, - 0x0000000000000403, 0x0000000004020100, 0x0000000000040201, - 0x0000000000040200, 0x0000000000000402, 0x0000000000040100, - 0x0000000000000401, 0x0000000000000400, 0x0000000000000004, - 0x0000000003020100, 0x0000000000030201, 0x0000000000030200, - 0x0000000000000302, 0x0000000000030100, 0x0000000000000301, - 0x0000000000000300, 0x0000000000000003, 0x0000000000020100, - 0x0000000000000201, 0x0000000000000200, 0x0000000000000002, - 0x0000000000000100, 0x0000000000000001, 0x0000000000000000, +constexpr uint64_t thintableEpi8[256] = { + 0x0706050403020100, 0x0007060504030201, 0x0007060504030200, 0x0000070605040302, 0x0007060504030100, + 0x0000070605040301, 0x0000070605040300, 0x0000000706050403, 0x0007060504020100, 0x0000070605040201, + 0x0000070605040200, 0x0000000706050402, 0x0000070605040100, 0x0000000706050401, 0x0000000706050400, + 0x0000000007060504, 0x0007060503020100, 0x0000070605030201, 0x0000070605030200, 0x0000000706050302, + 0x0000070605030100, 0x0000000706050301, 0x0000000706050300, 0x0000000007060503, 0x0000070605020100, + 0x0000000706050201, 0x0000000706050200, 0x0000000007060502, 0x0000000706050100, 0x0000000007060501, + 0x0000000007060500, 0x0000000000070605, 0x0007060403020100, 0x0000070604030201, 0x0000070604030200, + 0x0000000706040302, 0x0000070604030100, 0x0000000706040301, 0x0000000706040300, 0x0000000007060403, + 0x0000070604020100, 0x0000000706040201, 0x0000000706040200, 0x0000000007060402, 0x0000000706040100, + 0x0000000007060401, 0x0000000007060400, 0x0000000000070604, 0x0000070603020100, 0x0000000706030201, + 0x0000000706030200, 0x0000000007060302, 0x0000000706030100, 0x0000000007060301, 0x0000000007060300, + 0x0000000000070603, 0x0000000706020100, 0x0000000007060201, 0x0000000007060200, 0x0000000000070602, + 0x0000000007060100, 0x0000000000070601, 0x0000000000070600, 0x0000000000000706, 0x0007050403020100, + 0x0000070504030201, 0x0000070504030200, 0x0000000705040302, 0x0000070504030100, 0x0000000705040301, + 0x0000000705040300, 0x0000000007050403, 0x0000070504020100, 0x0000000705040201, 0x0000000705040200, + 0x0000000007050402, 0x0000000705040100, 0x0000000007050401, 0x0000000007050400, 0x0000000000070504, + 0x0000070503020100, 0x0000000705030201, 0x0000000705030200, 0x0000000007050302, 0x0000000705030100, + 0x0000000007050301, 0x0000000007050300, 0x0000000000070503, 0x0000000705020100, 0x0000000007050201, + 0x0000000007050200, 0x0000000000070502, 0x0000000007050100, 0x0000000000070501, 0x0000000000070500, + 0x0000000000000705, 0x0000070403020100, 0x0000000704030201, 0x0000000704030200, 0x0000000007040302, + 0x0000000704030100, 0x0000000007040301, 0x0000000007040300, 0x0000000000070403, 0x0000000704020100, + 0x0000000007040201, 0x0000000007040200, 0x0000000000070402, 0x0000000007040100, 0x0000000000070401, + 0x0000000000070400, 0x0000000000000704, 0x0000000703020100, 0x0000000007030201, 0x0000000007030200, + 0x0000000000070302, 0x0000000007030100, 0x0000000000070301, 0x0000000000070300, 0x0000000000000703, + 0x0000000007020100, 0x0000000000070201, 0x0000000000070200, 0x0000000000000702, 0x0000000000070100, + 0x0000000000000701, 0x0000000000000700, 0x0000000000000007, 0x0006050403020100, 0x0000060504030201, + 0x0000060504030200, 0x0000000605040302, 0x0000060504030100, 0x0000000605040301, 0x0000000605040300, + 0x0000000006050403, 0x0000060504020100, 0x0000000605040201, 0x0000000605040200, 0x0000000006050402, + 0x0000000605040100, 0x0000000006050401, 0x0000000006050400, 0x0000000000060504, 0x0000060503020100, + 0x0000000605030201, 0x0000000605030200, 0x0000000006050302, 0x0000000605030100, 0x0000000006050301, + 0x0000000006050300, 0x0000000000060503, 0x0000000605020100, 0x0000000006050201, 0x0000000006050200, + 0x0000000000060502, 0x0000000006050100, 0x0000000000060501, 0x0000000000060500, 0x0000000000000605, + 0x0000060403020100, 0x0000000604030201, 0x0000000604030200, 0x0000000006040302, 0x0000000604030100, + 0x0000000006040301, 0x0000000006040300, 0x0000000000060403, 0x0000000604020100, 0x0000000006040201, + 0x0000000006040200, 0x0000000000060402, 0x0000000006040100, 0x0000000000060401, 0x0000000000060400, + 0x0000000000000604, 0x0000000603020100, 0x0000000006030201, 0x0000000006030200, 0x0000000000060302, + 0x0000000006030100, 0x0000000000060301, 0x0000000000060300, 0x0000000000000603, 0x0000000006020100, + 0x0000000000060201, 0x0000000000060200, 0x0000000000000602, 0x0000000000060100, 0x0000000000000601, + 0x0000000000000600, 0x0000000000000006, 0x0000050403020100, 0x0000000504030201, 0x0000000504030200, + 0x0000000005040302, 0x0000000504030100, 0x0000000005040301, 0x0000000005040300, 0x0000000000050403, + 0x0000000504020100, 0x0000000005040201, 0x0000000005040200, 0x0000000000050402, 0x0000000005040100, + 0x0000000000050401, 0x0000000000050400, 0x0000000000000504, 0x0000000503020100, 0x0000000005030201, + 0x0000000005030200, 0x0000000000050302, 0x0000000005030100, 0x0000000000050301, 0x0000000000050300, + 0x0000000000000503, 0x0000000005020100, 0x0000000000050201, 0x0000000000050200, 0x0000000000000502, + 0x0000000000050100, 0x0000000000000501, 0x0000000000000500, 0x0000000000000005, 0x0000000403020100, + 0x0000000004030201, 0x0000000004030200, 0x0000000000040302, 0x0000000004030100, 0x0000000000040301, + 0x0000000000040300, 0x0000000000000403, 0x0000000004020100, 0x0000000000040201, 0x0000000000040200, + 0x0000000000000402, 0x0000000000040100, 0x0000000000000401, 0x0000000000000400, 0x0000000000000004, + 0x0000000003020100, 0x0000000000030201, 0x0000000000030200, 0x0000000000000302, 0x0000000000030100, + 0x0000000000000301, 0x0000000000000300, 0x0000000000000003, 0x0000000000020100, 0x0000000000000201, + 0x0000000000000200, 0x0000000000000002, 0x0000000000000100, 0x0000000000000001, 0x0000000000000000, 0x0000000000000000, }; -constexpr uint8_t pshufb_combine_table[272] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x01, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +constexpr uint8_t pshufbCombineTable[272] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; -constexpr unsigned char BitsSetTable256mul2[256] = { - 0, 2, 2, 4, 2, 4, 4, 6, 2, 4, 4, 6, 4, 6, 6, 8, 2, 4, 4, - 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 2, 4, 4, 6, 4, 6, - 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, 6, - 8, 8, 10, 8, 10, 10, 12, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, - 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, - 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 6, 8, - 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 2, 4, 4, 6, 4, - 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, - 6, 8, 8, 10, 8, 10, 10, 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, - 10, 8, 10, 10, 12, 6, 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, - 12, 14, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 6, - 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 6, 8, 8, 10, - 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 8, 10, 10, 12, 10, 12, 12, - 14, 10, 12, 12, 14, 12, 14, 14, 16}; - -constexpr uint8_t to_base64_value[] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, - 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255}; - -constexpr uint8_t to_base64_url_value[] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 62, 255, 255, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255}; - -constexpr uint8_t to_base64_default_or_url_value[] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, - 62, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255}; - -static_assert(sizeof(to_base64_value) == 256, - "to_base64_value must have 256 elements"); -static_assert(sizeof(to_base64_url_value) == 256, - "to_base64_url_value must have 256 elements"); -static_assert(to_base64_value[uint8_t(' ')] == 64, - "space must be == 64 in to_base64_value"); -static_assert(to_base64_url_value[uint8_t(' ')] == 64, - "space must be == 64 in to_base64_url_value"); -static_assert(to_base64_value[uint8_t('\t')] == 64, - "tab must be == 64 in to_base64_value"); -static_assert(to_base64_url_value[uint8_t('\t')] == 64, - "tab must be == 64 in to_base64_url_value"); -static_assert(to_base64_value[uint8_t('\r')] == 64, - "cr must be == 64 in to_base64_value"); -static_assert(to_base64_url_value[uint8_t('\r')] == 64, - "cr must be == 64 in to_base64_url_value"); -static_assert(to_base64_value[uint8_t('\n')] == 64, - "lf must be == 64 in to_base64_value"); -static_assert(to_base64_url_value[uint8_t('\n')] == 64, - "lf must be == 64 in to_base64_url_value"); -static_assert(to_base64_value[uint8_t('\f')] == 64, - "ff must be == 64 in to_base64_value"); -static_assert(to_base64_url_value[uint8_t('\f')] == 64, - "ff must be == 64 in to_base64_url_value"); -static_assert(to_base64_value[uint8_t('+')] == 62, - "+ must be == 62 in to_base64_value"); -static_assert(to_base64_url_value[uint8_t('-')] == 62, - "- must be == 62 in to_base64_url_value"); -static_assert(to_base64_value[uint8_t('/')] == 63, - "/ must be == 63 in to_base64_value"); -static_assert(to_base64_url_value[uint8_t('_')] == 63, - "_ must be == 63 in to_base64_url_value"); -} // namespace base64 -} // namespace tables +constexpr unsigned char bitsSetTable256mul2[256] = { + 0, 2, 2, 4, 2, 4, 4, 6, 2, 4, 4, 6, 4, 6, 6, 8, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, + 8, 8, 10, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, + 8, 10, 8, 10, 10, 12, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, + 10, 6, 8, 8, 10, 8, 10, 10, 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 6, 8, 8, 10, + 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, + 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, + 10, 12, 6, 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, + 10, 8, 10, 10, 12, 6, 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 6, 8, 8, 10, 8, 10, 10, 12, + 8, 10, 10, 12, 10, 12, 12, 14, 8, 10, 10, 12, 10, 12, 12, 14, 10, 12, 12, 14, 12, 14, 14, 16}; + +constexpr uint8_t toBase64Value[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, + 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; + +constexpr uint8_t toBase64UrlValue[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 62, 255, 255, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; + +constexpr uint8_t toBase64DefaultOrUrlValue[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, + 255, 62, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; + +static_assert(sizeof(toBase64Value) == 256, "to_base64_value must have 256 elements"); +static_assert(sizeof(toBase64UrlValue) == 256, "to_base64_url_value must have 256 elements"); +static_assert(toBase64Value[static_cast(' ')] == 64, "space must be == 64 in to_base64_value"); +static_assert(toBase64UrlValue[static_cast(' ')] == 64, "space must be == 64 in to_base64_url_value"); +static_assert(toBase64Value[static_cast('\t')] == 64, "tab must be == 64 in to_base64_value"); +static_assert(toBase64UrlValue[static_cast('\t')] == 64, "tab must be == 64 in to_base64_url_value"); +static_assert(toBase64Value[static_cast('\r')] == 64, "cr must be == 64 in to_base64_value"); +static_assert(toBase64UrlValue[static_cast('\r')] == 64, "cr must be == 64 in to_base64_url_value"); +static_assert(toBase64Value[static_cast('\n')] == 64, "lf must be == 64 in to_base64_value"); +static_assert(toBase64UrlValue[static_cast('\n')] == 64, "lf must be == 64 in to_base64_url_value"); +static_assert(toBase64Value[static_cast('\f')] == 64, "ff must be == 64 in to_base64_value"); +static_assert(toBase64UrlValue[static_cast('\f')] == 64, "ff must be == 64 in to_base64_url_value"); +static_assert(toBase64Value[static_cast('+')] == 62, "+ must be == 62 in to_base64_value"); +static_assert(toBase64UrlValue[static_cast('-')] == 62, "- must be == 62 in to_base64_url_value"); +static_assert(toBase64Value[static_cast('/')] == 63, "/ must be == 63 in to_base64_value"); +static_assert(toBase64UrlValue[static_cast('_')] == 63, "_ must be == 63 in to_base64_url_value"); +} // namespace tables::base64 + } // unnamed namespace } // namespace simdutf @@ -9952,89 +9289,69 @@ static_assert(to_base64_url_value[uint8_t('_')] == 63, #include #include -namespace simdutf { -namespace scalar { +namespace simdutf::scalar { namespace { namespace base64 { // This function is not expected to be fast. Do not use in long loops. // In most instances you should be using is_ignorable. -template bool is_ascii_white_space(char_type c) { - return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'; -} - -template simdutf_constexpr23 bool is_eight_byte(char_type c) { - if constexpr (sizeof(char_type) == 1) { - return true; - } - return uint8_t(c) == c; +template auto is_ascii_white_space(char_type c) -> bool { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'; } -template -simdutf_constexpr23 bool is_ignorable(char_type c, - simdutf::base64_options options) { - const uint8_t *to_base64 = - (options & base64_default_or_url) - ? tables::base64::to_base64_default_or_url_value - : ((options & base64_url) ? tables::base64::to_base64_url_value - : tables::base64::to_base64_value); - const bool ignore_garbage = - (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - uint8_t code = to_base64[uint8_t(c)]; - if (is_eight_byte(c) && code <= 63) { - return false; - } - if (is_eight_byte(c) && code == 64) { - return true; - } - return ignore_garbage; +template simdutf_constexpr23 auto is_eight_byte(char_type c) -> bool { + if constexpr (sizeof(char_type) == 1) { + return true; + } + return uint8_t(c) == c; +} + +template simdutf_constexpr23 auto is_ignorable(char_type c, simdutf::base64_options options) -> bool { + const uint8_t* toBase64 = (options & base64_default_or_url) + ? tables::base64::toBase64DefaultOrUrlValue + : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); + const bool ignoreGarbage = (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + uint8_t code = toBase64[uint8_t(c)]; + if (is_eight_byte(c) && code <= 63) { + return false; + } + if (is_eight_byte(c) && code == 64) { + return true; + } + return ignoreGarbage; } -template -simdutf_constexpr23 bool is_base64(char_type c, - simdutf::base64_options options) { - const uint8_t *to_base64 = - (options & base64_default_or_url) - ? tables::base64::to_base64_default_or_url_value - : ((options & base64_url) ? tables::base64::to_base64_url_value - : tables::base64::to_base64_value); - uint8_t code = to_base64[uint8_t(c)]; - if (is_eight_byte(c) && code <= 63) { - return true; - } - return false; +template simdutf_constexpr23 auto is_base64(char_type c, simdutf::base64_options options) -> bool { + const uint8_t* toBase64 = (options & base64_default_or_url) + ? tables::base64::toBase64DefaultOrUrlValue + : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); + uint8_t code = toBase64[uint8_t(c)]; + return static_cast(is_eight_byte(c) && code <= 63); } template -simdutf_constexpr23 bool is_base64_or_padding(char_type c, - simdutf::base64_options options) { - const uint8_t *to_base64 = - (options & base64_default_or_url) - ? tables::base64::to_base64_default_or_url_value - : ((options & base64_url) ? tables::base64::to_base64_url_value - : tables::base64::to_base64_value); - if (c == '=') { - return true; - } - uint8_t code = to_base64[uint8_t(c)]; - if (is_eight_byte(c) && code <= 63) { - return true; - } - return false; +simdutf_constexpr23 auto is_base64_or_padding(char_type c, simdutf::base64_options options) -> bool { + const uint8_t* toBase64 = (options & base64_default_or_url) + ? tables::base64::toBase64DefaultOrUrlValue + : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); + if (c == '=') { + return true; + } + uint8_t code = toBase64[uint8_t(c)]; + return static_cast(is_eight_byte(c) && code <= 63); } -template -bool is_ignorable_or_padding(char_type c, simdutf::base64_options options) { - return is_ignorable(c, options) || c == '='; +template auto is_ignorable_or_padding(char_type c, simdutf::base64_options options) -> bool { + return is_ignorable(c, options) || c == '='; } struct reduced_input { size_t equalsigns; // number of padding characters '=', typically 0, 1, 2. size_t equallocation; // location of the first padding character if any size_t srclen; // length of the input buffer before padding - size_t full_input_length; // length of the input buffer with padding but - // without ignorable characters + size_t fullInputLength; // length of the input buffer with padding but + // without ignorable characters }; // find the end of the base64 input buffer @@ -10043,60 +9360,61 @@ struct reduced_input { // and the length of the input buffer with padding. The input buffer is not // modified. The function assumes that there are at most two padding characters. template -simdutf_constexpr23 reduced_input find_end(const char_type *src, size_t srclen, - simdutf::base64_options options) { - const uint8_t *to_base64 = - (options & base64_default_or_url) - ? tables::base64::to_base64_default_or_url_value - : ((options & base64_url) ? tables::base64::to_base64_url_value - : tables::base64::to_base64_value); - const bool ignore_garbage = - (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - - size_t equalsigns = 0; - // We intentionally include trailing spaces in the full input length. - // See https://github.com/simdutf/simdutf/issues/824 - size_t full_input_length = srclen; - // skip trailing spaces - while (!ignore_garbage && srclen > 0 && - scalar::base64::is_eight_byte(src[srclen - 1]) && - to_base64[uint8_t(src[srclen - 1])] == 64) { - srclen--; - } - size_t equallocation = - srclen; // location of the first padding character if any - if (ignore_garbage) { - // Technically, we don't need to find the first padding character, we can - // just change our algorithms, but it adds substantial complexity. - auto it = simdutf::find(src, src + srclen, '='); - if (it != src + srclen) { - equallocation = it - src; - equalsigns = 1; - srclen = equallocation; - full_input_length = equallocation + 1; - } - return {equalsigns, equallocation, srclen, full_input_length}; - } - if (!ignore_garbage && srclen > 0 && src[srclen - 1] == '=') { - // This is the last '=' sign. - equallocation = srclen - 1; - srclen--; - equalsigns = 1; +simdutf_constexpr23 auto find_end(const char_type* src, size_t srclen, simdutf::base64_options options) + -> reduced_input { + const uint8_t* toBase64 = (options & base64_default_or_url) + ? tables::base64::toBase64DefaultOrUrlValue + : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); + const bool ignoreGarbage = (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + + size_t equalsigns = 0; + // We intentionally include trailing spaces in the full input length. + // See https://github.com/simdutf/simdutf/issues/824 + size_t fullInputLength = srclen; // skip trailing spaces - while (srclen > 0 && scalar::base64::is_eight_byte(src[srclen - 1]) && - to_base64[uint8_t(src[srclen - 1])] == 64) { - srclen--; + while (!ignoreGarbage && srclen > 0 && scalar::base64::is_eight_byte(src[srclen - 1]) && + toBase64[uint8_t(src[srclen - 1])] == 64) { + srclen--; } - if (srclen > 0 && src[srclen - 1] == '=') { - // This is the second '=' sign. - equallocation = srclen - 1; - srclen--; - equalsigns = 2; + size_t equallocation = srclen; // location of the first padding character if any + if (ignoreGarbage) { + // Technically, we don't need to find the first padding character, we can + // just change our algorithms, but it adds substantial complexity. + auto it = simdutf::find(src, src + srclen, '='); + if (it != src + srclen) { + equallocation = it - src; + equalsigns = 1; + srclen = equallocation; + fullInputLength = equallocation + 1; + } + return {.equalsigns = equalsigns, + .equallocation = equallocation, + .srclen = srclen, + .full_input_length = fullInputLength}; } - } - return {equalsigns, equallocation, srclen, full_input_length}; + if (!ignoreGarbage && srclen > 0 && src[srclen - 1] == '=') { + // This is the last '=' sign. + equallocation = srclen - 1; + srclen--; + equalsigns = 1; + // skip trailing spaces + while (srclen > 0 && scalar::base64::is_eight_byte(src[srclen - 1]) && + toBase64[uint8_t(src[srclen - 1])] == 64) { + srclen--; + } + if (srclen > 0 && src[srclen - 1] == '=') { + // This is the second '=' sign. + equallocation = srclen - 1; + srclen--; + equalsigns = 2; + } + } + return {.equalsigns = equalsigns, + .equallocation = equallocation, + .srclen = srclen, + .full_input_length = fullInputLength}; } // Returns true upon success. The destination buffer must be large enough. @@ -10104,70 +9422,57 @@ simdutf_constexpr23 reduced_input find_end(const char_type *src, size_t srclen, // if check_capacity is true, it will check that the destination buffer is // large enough. If it is not, it will return OUTPUT_BUFFER_TOO_SMALL. template -simdutf_constexpr23 full_result base64_tail_decode_impl( - char *dst, size_t outlen, const char_type *src, size_t length, - size_t padding_characters, // number of padding characters - // '=', typically 0, 1, 2. - base64_options options, last_chunk_handling_options last_chunk_options) { - char *dstend = dst + outlen; - (void)dstend; - // This looks like 10 branches, but we expect the compiler to resolve this to - // two branches (easily predicted): - const uint8_t *to_base64 = - (options & base64_default_or_url) - ? tables::base64::to_base64_default_or_url_value - : ((options & base64_url) ? tables::base64::to_base64_url_value - : tables::base64::to_base64_value); - const uint32_t *d0 = - (options & base64_default_or_url) - ? tables::base64::base64_default_or_url::d0 - : ((options & base64_url) ? tables::base64::base64_url::d0 - : tables::base64::base64_default::d0); - const uint32_t *d1 = - (options & base64_default_or_url) - ? tables::base64::base64_default_or_url::d1 - : ((options & base64_url) ? tables::base64::base64_url::d1 - : tables::base64::base64_default::d1); - const uint32_t *d2 = - (options & base64_default_or_url) - ? tables::base64::base64_default_or_url::d2 - : ((options & base64_url) ? tables::base64::base64_url::d2 - : tables::base64::base64_default::d2); - const uint32_t *d3 = - (options & base64_default_or_url) - ? tables::base64::base64_default_or_url::d3 - : ((options & base64_url) ? tables::base64::base64_url::d3 - : tables::base64::base64_default::d3); - const bool ignore_garbage = - (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - - const char_type *srcend = src + length; - const char_type *srcinit = src; - const char *dstinit = dst; - - uint32_t x; - size_t idx; - uint8_t buffer[4]; - while (true) { - while (srcend - src >= 4 && is_eight_byte(src[0]) && - is_eight_byte(src[1]) && is_eight_byte(src[2]) && - is_eight_byte(src[3]) && - (x = d0[uint8_t(src[0])] | d1[uint8_t(src[1])] | - d2[uint8_t(src[2])] | d3[uint8_t(src[3])]) < 0x01FFFFFF) { - if (check_capacity && dstend - dst < 3) { - return {OUTPUT_BUFFER_TOO_SMALL, size_t(src - srcinit), - size_t(dst - dstinit)}; - } - *dst++ = static_cast(x & 0xFF); - *dst++ = static_cast((x >> 8) & 0xFF); - *dst++ = static_cast((x >> 16) & 0xFF); - src += 4; - } - const char_type *srccur = src; - idx = 0; - // we need at least four characters. +simdutf_constexpr23 auto base64_tail_decode_impl(char* dst, size_t outlen, const char_type* src, size_t length, + size_t padding_characters, // number of padding characters + // '=', typically 0, 1, 2. + base64_options options, last_chunk_handling_options last_chunk_options) + -> full_result { + char* dstend = dst + outlen; + (void)dstend; + // This looks like 10 branches, but we expect the compiler to resolve this to + // two branches (easily predicted): + const uint8_t* toBase64 = (options & base64_default_or_url) + ? tables::base64::toBase64DefaultOrUrlValue + : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); + const uint32_t* d0 = (options & base64_default_or_url) + ? tables::base64::base64_default_or_url::d0 + : ((options & base64_url) ? tables::base64::base64_url::d0 : tables::base64::base64_default::d0); + const uint32_t* d1 = (options & base64_default_or_url) + ? tables::base64::base64_default_or_url::d1 + : ((options & base64_url) ? tables::base64::base64_url::d1 : tables::base64::base64_default::d1); + const uint32_t* d2 = (options & base64_default_or_url) + ? tables::base64::base64_default_or_url::d2 + : ((options & base64_url) ? tables::base64::base64_url::d2 : tables::base64::base64_default::d2); + const uint32_t* d3 = (options & base64_default_or_url) + ? tables::base64::base64_default_or_url::d3 + : ((options & base64_url) ? tables::base64::base64_url::d3 : tables::base64::base64_default::d3); + const bool ignore_garbage = (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + + const char_type* srcend = src + length; + const char_type* srcinit = src; + const char* dstinit = dst; + + uint32_t x = 0; + size_t idx = 0; + uint8_t buffer[4]; + while (true) { + while (srcend - src >= 4 && is_eight_byte(src[0]) && is_eight_byte(src[1]) && is_eight_byte(src[2]) && + is_eight_byte(src[3]) && + (x = d0[uint8_t(src[0])] | d1[uint8_t(src[1])] | d2[uint8_t(src[2])] | d3[uint8_t(src[3])]) < + 0x01FFFFFF) { + if (check_capacity && dstend - dst < 3) { + return {OUTPUT_BUFFER_TOO_SMALL, size_t(src - srcinit), static_cast(dst - dstinit)}; + } + *dst++ = static_cast(x & 0xFF); + *dst++ = static_cast((x >> 8) & 0xFF); + *dst++ = static_cast((x >> 16) & 0xFF); + src += 4; + } + const char_type* srccur = src; + idx = 0; + // we need at least four characters. #ifdef __clang__ // If possible, we read four characters at a time. (It is an optimization.) if (ignore_garbage && src + 4 <= srcend) { @@ -10176,10 +9481,10 @@ simdutf_constexpr23 full_result base64_tail_decode_impl( char_type c2 = src[2]; char_type c3 = src[3]; - uint8_t code0 = to_base64[uint8_t(c0)]; - uint8_t code1 = to_base64[uint8_t(c1)]; - uint8_t code2 = to_base64[uint8_t(c2)]; - uint8_t code3 = to_base64[uint8_t(c3)]; + uint8_t code0 = toBase64[uint8_t(c0)]; + uint8_t code1 = toBase64[uint8_t(c1)]; + uint8_t code2 = toBase64[uint8_t(c2)]; + uint8_t code3 = toBase64[uint8_t(c3)]; buffer[idx] = code0; idx += (is_eight_byte(c0) && code0 <= 63); @@ -10195,14 +9500,13 @@ simdutf_constexpr23 full_result base64_tail_decode_impl( while ((idx < 4) && (src < srcend)) { char_type c = *src; - uint8_t code = to_base64[uint8_t(c)]; - buffer[idx] = uint8_t(code); + uint8_t code = toBase64[uint8_t(c)]; + buffer[idx] = code; if (is_eight_byte(c) && code <= 63) { idx++; } else if (!ignore_garbage && (code > 64 || !scalar::base64::is_eight_byte(c))) { - return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), - size_t(dst - dstinit)}; + return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), static_cast(dst - dstinit)}; } else { // We have a space or a newline or garbage. We ignore it. } @@ -10213,8 +9517,7 @@ simdutf_constexpr23 full_result base64_tail_decode_impl( // We never should have that the number of base64 characters + the // number of padding characters is more than 4. if (!ignore_garbage && (idx + padding_characters > 4)) { - return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), - size_t(dst - dstinit), true}; + return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), static_cast(dst - dstinit), true}; } // The idea here is that in loose mode, @@ -10225,85 +9528,66 @@ simdutf_constexpr23 full_result base64_tail_decode_impl( last_chunk_options == last_chunk_handling_options::loose && (idx >= 2) && padding_characters > 0 && ((idx + padding_characters) & 3) != 0) { - return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), - size_t(dst - dstinit), true}; - } else + return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), static_cast(dst - dstinit), true}; + } - // The idea here is that in strict mode, we do not want to accept - // incomplete base64 chunks. So if the chunk was otherwise valid, we - // return BASE64_INPUT_REMAINDER. - if (!ignore_garbage && - last_chunk_options == last_chunk_handling_options::strict && - (idx >= 2) && ((idx + padding_characters) & 3) != 0) { + // The idea here is that in strict mode, we do not want to accept + // incomplete base64 chunks. So if the chunk was otherwise valid, we + // return BASE64_INPUT_REMAINDER. + if (!ignore_garbage && last_chunk_options == last_chunk_handling_options::strict && (idx >= 2) && + ((idx + padding_characters) & 3) != 0) { // The partial chunk was at src - idx - return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), - size_t(dst - dstinit), true}; - } else + return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), size_t(dst - dstinit), true}; + } else // If there is a partial chunk with insufficient padding, with // stop_before_partial, we need to just ignore it. In "only full" // mode, skip the minute there are padding characters. - if ((last_chunk_options == - last_chunk_handling_options::stop_before_partial && - (padding_characters + idx < 4) && (idx != 0) && - (idx >= 2 || padding_characters == 0)) || - (last_chunk_options == - last_chunk_handling_options::only_full_chunks && + if ((last_chunk_options == last_chunk_handling_options::stop_before_partial && + (padding_characters + idx < 4) && (idx != 0) && (idx >= 2 || padding_characters == 0)) || + (last_chunk_options == last_chunk_handling_options::only_full_chunks && (idx >= 2 || padding_characters == 0))) { - // partial means that we are *not* going to consume the read - // characters. We need to rewind the src pointer. - src = srccur; - return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; + // partial means that we are *not* going to consume the read + // characters. We need to rewind the src pointer. + src = srccur; + return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; } else { - if (idx == 2) { - uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + - (uint32_t(buffer[1]) << 2 * 6); - if (!ignore_garbage && - (last_chunk_options == last_chunk_handling_options::strict) && - (triple & 0xffff)) { - return {BASE64_EXTRA_BITS, size_t(src - srcinit), - size_t(dst - dstinit)}; - } - if (check_capacity && dstend - dst < 1) { - return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), - size_t(dst - dstinit)}; + if (idx == 2) { + uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + (uint32_t(buffer[1]) << 2 * 6); + if (!ignore_garbage && (last_chunk_options == last_chunk_handling_options::strict) && + (triple & 0xffff)) { + return {BASE64_EXTRA_BITS, size_t(src - srcinit), size_t(dst - dstinit)}; + } + if (check_capacity && dstend - dst < 1) { + return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), size_t(dst - dstinit)}; + } + *dst++ = static_cast((triple >> 16) & 0xFF); + } else if (idx == 3) { + uint32_t triple = + (uint32_t(buffer[0]) << 3 * 6) + (uint32_t(buffer[1]) << 2 * 6) + (uint32_t(buffer[2]) << 1 * 6); + if (!ignore_garbage && (last_chunk_options == last_chunk_handling_options::strict) && + (triple & 0xff)) { + return {BASE64_EXTRA_BITS, size_t(src - srcinit), size_t(dst - dstinit)}; + } + if (check_capacity && dstend - dst < 2) { + return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), size_t(dst - dstinit)}; + } + *dst++ = static_cast((triple >> 16) & 0xFF); + *dst++ = static_cast((triple >> 8) & 0xFF); + } else if (!ignore_garbage && idx == 1 && + (!is_partial(last_chunk_options) || + (is_partial(last_chunk_options) && padding_characters > 0))) { + return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), size_t(dst - dstinit)}; + } else if (!ignore_garbage && idx == 0 && padding_characters > 0) { + return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), size_t(dst - dstinit), true}; } - *dst++ = static_cast((triple >> 16) & 0xFF); - } else if (idx == 3) { - uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + - (uint32_t(buffer[1]) << 2 * 6) + - (uint32_t(buffer[2]) << 1 * 6); - if (!ignore_garbage && - (last_chunk_options == last_chunk_handling_options::strict) && - (triple & 0xff)) { - return {BASE64_EXTRA_BITS, size_t(src - srcinit), - size_t(dst - dstinit)}; - } - if (check_capacity && dstend - dst < 2) { - return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), - size_t(dst - dstinit)}; - } - *dst++ = static_cast((triple >> 16) & 0xFF); - *dst++ = static_cast((triple >> 8) & 0xFF); - } else if (!ignore_garbage && idx == 1 && - (!is_partial(last_chunk_options) || - (is_partial(last_chunk_options) && - padding_characters > 0))) { - return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), - size_t(dst - dstinit)}; - } else if (!ignore_garbage && idx == 0 && padding_characters > 0) { - return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), - size_t(dst - dstinit), true}; - } - return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; + return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; } } if (check_capacity && dstend - dst < 3) { - return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), - size_t(dst - dstinit)}; + return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), static_cast(dst - dstinit)}; } - uint32_t triple = - (uint32_t(buffer[0]) << 3 * 6) + (uint32_t(buffer[1]) << 2 * 6) + - (uint32_t(buffer[2]) << 1 * 6) + (uint32_t(buffer[3]) << 0 * 6); + uint32_t triple = (static_cast(buffer[0]) << 3 * 6) + (static_cast(buffer[1]) << 2 * 6) + + (static_cast(buffer[2]) << 1 * 6) + (static_cast(buffer[3]) << 0 * 6); *dst++ = static_cast((triple >> 16) & 0xFF); *dst++ = static_cast((triple >> 8) & 0xFF); *dst++ = static_cast(triple & 0xFF); @@ -10311,13 +9595,12 @@ simdutf_constexpr23 full_result base64_tail_decode_impl( } template -simdutf_constexpr23 full_result base64_tail_decode( - char *dst, const char_type *src, size_t length, - size_t padding_characters, // number of padding characters - // '=', typically 0, 1, 2. - base64_options options, last_chunk_handling_options last_chunk_options) { - return base64_tail_decode_impl(dst, 0, src, length, padding_characters, - options, last_chunk_options); +simdutf_constexpr23 auto base64_tail_decode(char* dst, const char_type* src, size_t length, + size_t paddingCharacters, // number of padding characters + // '=', typically 0, 1, 2. + base64_options options, last_chunk_handling_options lastChunkOptions) + -> full_result { + return base64_tail_decode_impl(dst, 0, src, length, paddingCharacters, options, lastChunkOptions); } // like base64_tail_decode, but it will not write past the end of the output @@ -10325,318 +9608,308 @@ simdutf_constexpr23 full_result base64_tail_decode( // written. This functions assumes that the padding (=) has been removed. // template -simdutf_constexpr23 full_result base64_tail_decode_safe( - char *dst, size_t outlen, const char_type *src, size_t length, - size_t padding_characters, // number of padding characters - // '=', typically 0, 1, 2. - base64_options options, last_chunk_handling_options last_chunk_options) { - return base64_tail_decode_impl(dst, outlen, src, length, - padding_characters, options, - last_chunk_options); -} - -inline simdutf_constexpr23 full_result -patch_tail_result(full_result r, size_t previous_input, size_t previous_output, - size_t equallocation, size_t full_input_length, - last_chunk_handling_options last_chunk_options) { - r.input_count += previous_input; - r.output_count += previous_output; - if (r.padding_error) { - r.input_count = equallocation; - } +simdutf_constexpr23 auto base64_tail_decode_safe(char* dst, size_t outlen, const char_type* src, size_t length, + size_t paddingCharacters, // number of padding characters + // '=', typically 0, 1, 2. + base64_options options, last_chunk_handling_options lastChunkOptions) + -> full_result { + return base64_tail_decode_impl(dst, outlen, src, length, paddingCharacters, options, lastChunkOptions); +} + +simdutf_constexpr23 auto patch_tail_result(full_result r, size_t previousInput, size_t previousOutput, + size_t equallocation, size_t fullInputLength, + last_chunk_handling_options lastChunkOptions) -> full_result { + r.input_count += previousInput; + r.outputCount += previousOutput; + if (r.paddingError) { + r.input_count = equallocation; + } - if (r.error == error_code::SUCCESS) { - if (!is_partial(last_chunk_options)) { - // A success when we are not in stop_before_partial mode. - // means that we have consumed the whole input buffer. - r.input_count = full_input_length; - } else if (r.output_count % 3 != 0) { - r.input_count = full_input_length; + if (r.error == error_code::SUCCESS) { + if (!is_partial(lastChunkOptions)) { + // A success when we are not in stop_before_partial mode. + // means that we have consumed the whole input buffer. + r.input_count = fullInputLength; + } else if (r.outputCount % 3 != 0) { + r.input_count = fullInputLength; + } } - } - return r; + return r; } // Returns the number of bytes written. The destination buffer must be large // enough. It will add padding (=) if needed. template -simdutf_constexpr23 size_t tail_encode_base64_impl( - char *dst, const char *src, size_t srclen, base64_options options, - size_t line_length = simdutf::default_line_length, size_t line_offset = 0) { - if constexpr (use_lines) { - // sanitize line_length and starting_line_offset. - // line_length must be greater than 3. - if (line_length < 4) { - line_length = 4; - } - simdutf_log_assert(line_offset <= line_length, - "line_offset should be less than line_length"); - } - // By default, we use padding if we are not using the URL variant. - // This is check with ((options & base64_url) == 0) which returns true if we - // are not using the URL variant. However, we also allow 'inversion' of the - // convention with the base64_reverse_padding option. If the - // base64_reverse_padding option is set, we use padding if we are using the - // URL variant, and we omit it if we are not using the URL variant. This is - // checked with - // ((options & base64_reverse_padding) == base64_reverse_padding). - bool use_padding = - ((options & base64_url) == 0) ^ - ((options & base64_reverse_padding) == base64_reverse_padding); - // This looks like 3 branches, but we expect the compiler to resolve this to - // a single branch: - const char *e0 = (options & base64_url) ? tables::base64::base64_url::e0 - : tables::base64::base64_default::e0; - const char *e1 = (options & base64_url) ? tables::base64::base64_url::e1 - : tables::base64::base64_default::e1; - const char *e2 = (options & base64_url) ? tables::base64::base64_url::e2 - : tables::base64::base64_default::e2; - char *out = dst; - size_t i = 0; - uint8_t t1, t2, t3; - for (; i + 2 < srclen; i += 3) { - t1 = uint8_t(src[i]); - t2 = uint8_t(src[i + 1]); - t3 = uint8_t(src[i + 2]); - if constexpr (use_lines) { - if (line_offset + 3 >= line_length) { - if (line_offset == line_length) { - *out++ = '\n'; - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - line_offset = 4; - } else if (line_offset + 1 == line_length) { - *out++ = e0[t1]; - *out++ = '\n'; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - line_offset = 3; - } else if (line_offset + 2 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = '\n'; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - line_offset = 2; - } else if (line_offset + 3 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = '\n'; - *out++ = e2[t3]; - line_offset = 1; - } - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - line_offset += 4; - } - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - } - } - switch (srclen - i) { - case 0: - break; - case 1: - t1 = uint8_t(src[i]); +simdutf_constexpr23 auto tail_encode_base64_impl(char* dst, const char* src, size_t srclen, base64_options options, + size_t line_length = simdutf::defaultLineLength, size_t lineOffset = 0) + -> size_t { if constexpr (use_lines) { - if (use_padding) { - if (line_offset + 3 >= line_length) { - if (line_offset == line_length) { - *out++ = '\n'; - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '='; - *out++ = '='; - } else if (line_offset + 1 == line_length) { - *out++ = e0[t1]; - *out++ = '\n'; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '='; - *out++ = '='; - } else if (line_offset + 2 == line_length) { - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '\n'; - *out++ = '='; - *out++ = '='; - } else if (line_offset + 3 == line_length) { - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '='; - *out++ = '\n'; - *out++ = '='; - } - } else { - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '='; - *out++ = '='; - } - } else { - if (line_offset + 2 >= line_length) { - if (line_offset == line_length) { - *out++ = '\n'; - *out++ = e0[uint8_t(src[i])]; - *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; - } else if (line_offset + 1 == line_length) { - *out++ = e0[uint8_t(src[i])]; - *out++ = '\n'; - *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; - } else { - *out++ = e0[uint8_t(src[i])]; - *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; - // *out++ = '\n'; ==> no newline at the end of the output - } - } else { - *out++ = e0[uint8_t(src[i])]; - *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; - } - } - } else { - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - if (use_padding) { - *out++ = '='; - *out++ = '='; - } + // sanitize line_length and starting_line_offset. + // line_length must be greater than 3. + line_length = std::max(line_length, 4); + simdutf_log_assert(line_offset <= line_length, "line_offset should be less than line_length"); } - break; - default: /* case 2 */ - t1 = uint8_t(src[i]); - t2 = uint8_t(src[i + 1]); - if constexpr (use_lines) { - if (use_padding) { - if (line_offset + 3 >= line_length) { - if (line_offset == line_length) { - *out++ = '\n'; - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '='; - } else if (line_offset + 1 == line_length) { - *out++ = e0[t1]; - *out++ = '\n'; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '='; - } else if (line_offset + 2 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = '\n'; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '='; - } else if (line_offset + 3 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '\n'; - *out++ = '='; - } + // By default, we use padding if we are not using the URL variant. + // This is check with ((options & base64_url) == 0) which returns true if we + // are not using the URL variant. However, we also allow 'inversion' of the + // convention with the base64_reverse_padding option. If the + // base64_reverse_padding option is set, we use padding if we are using the + // URL variant, and we omit it if we are not using the URL variant. This is + // checked with + // ((options & base64_reverse_padding) == base64_reverse_padding). + bool usePadding = ((options & base64_url) == 0) ^ ((options & base64ReversePadding) == base64ReversePadding); + // This looks like 3 branches, but we expect the compiler to resolve this to + // a single branch: + const char* e0 = (options & base64_url) ? tables::base64::base64_url::e0 : tables::base64::base64_default::e0; + const char* e1 = (options & base64_url) ? tables::base64::base64_url::e1 : tables::base64::base64_default::e1; + const char* e2 = (options & base64_url) ? tables::base64::base64_url::e2 : tables::base64::base64_default::e2; + char* out = dst; + size_t i = 0; + uint8_t t1; + uint8_t t2; + uint8_t t3; + for (; i + 2 < srclen; i += 3) { + t1 = static_cast(src[i]); + t2 = static_cast(src[i + 1]); + t3 = static_cast(src[i + 2]); + if constexpr (use_lines) { + if (lineOffset + 3 >= line_length) { + if (lineOffset == line_length) { + *out++ = '\n'; + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; + lineOffset = 4; + } else if (lineOffset + 1 == line_length) { + *out++ = e0[t1]; + *out++ = '\n'; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; + lineOffset = 3; + } else if (lineOffset + 2 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = '\n'; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; + lineOffset = 2; + } else if (lineOffset + 3 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = '\n'; + *out++ = e2[t3]; + lineOffset = 1; + } + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; + lineOffset += 4; + } } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '='; - } - } else { - if (line_offset + 3 >= line_length) { - if (line_offset == line_length) { - *out++ = '\n'; - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - } else if (line_offset + 1 == line_length) { - *out++ = e0[t1]; - *out++ = '\n'; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - } else if (line_offset + 2 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = '\n'; - *out++ = e2[(t2 & 0x0F) << 2]; - } else { *out++ = e0[t1]; *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - // *out++ = '\n'; ==> no newline at the end of the output - } - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; } - } - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - if (use_padding) { - *out++ = '='; - } } - } - return (size_t)(out - dst); + switch (srclen - i) { + case 0: + break; + case 1: + t1 = static_cast(src[i]); + if constexpr (use_lines) { + if (usePadding) { + if (lineOffset + 3 >= line_length) { + if (lineOffset == line_length) { + *out++ = '\n'; + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '='; + *out++ = '='; + } else if (lineOffset + 1 == line_length) { + *out++ = e0[t1]; + *out++ = '\n'; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '='; + *out++ = '='; + } else if (lineOffset + 2 == line_length) { + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '\n'; + *out++ = '='; + *out++ = '='; + } else if (lineOffset + 3 == line_length) { + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '='; + *out++ = '\n'; + *out++ = '='; + } + } else { + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '='; + *out++ = '='; + } + } else { + if (lineOffset + 2 >= line_length) { + if (lineOffset == line_length) { + *out++ = '\n'; + *out++ = e0[static_cast(src[i])]; + *out++ = e1[(static_cast(src[i]) & 0x03) << 4]; + } else if (lineOffset + 1 == line_length) { + *out++ = e0[static_cast(src[i])]; + *out++ = '\n'; + *out++ = e1[(static_cast(src[i]) & 0x03) << 4]; + } else { + *out++ = e0[static_cast(src[i])]; + *out++ = e1[(static_cast(src[i]) & 0x03) << 4]; + // *out++ = '\n'; ==> no newline at the end of the output + } + } else { + *out++ = e0[static_cast(src[i])]; + *out++ = e1[(static_cast(src[i]) & 0x03) << 4]; + } + } + } else { + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + if (usePadding) { + *out++ = '='; + *out++ = '='; + } + } + break; + default: /* case 2 */ + t1 = static_cast(src[i]); + t2 = static_cast(src[i + 1]); + if constexpr (use_lines) { + if (usePadding) { + if (lineOffset + 3 >= line_length) { + if (lineOffset == line_length) { + *out++ = '\n'; + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '='; + } else if (lineOffset + 1 == line_length) { + *out++ = e0[t1]; + *out++ = '\n'; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '='; + } else if (lineOffset + 2 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = '\n'; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '='; + } else if (lineOffset + 3 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '\n'; + *out++ = '='; + } + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '='; + } + } else { + if (lineOffset + 3 >= line_length) { + if (lineOffset == line_length) { + *out++ = '\n'; + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + } else if (lineOffset + 1 == line_length) { + *out++ = e0[t1]; + *out++ = '\n'; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + } else if (lineOffset + 2 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = '\n'; + *out++ = e2[(t2 & 0x0F) << 2]; + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + // *out++ = '\n'; ==> no newline at the end of the output + } + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + } + } + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + if (usePadding) { + *out++ = '='; + } + } + } + return static_cast(out - dst); } // Returns the number of bytes written. The destination buffer must be large // enough. It will add padding (=) if needed. -inline simdutf_constexpr23 size_t tail_encode_base64(char *dst, const char *src, - size_t srclen, - base64_options options) { - return tail_encode_base64_impl(dst, src, srclen, options); +simdutf_constexpr23 auto tail_encode_base64(char* dst, const char* src, size_t srclen, base64_options options) + -> size_t { + return tail_encode_base64_impl(dst, src, srclen, options); } template -simdutf_warn_unused simdutf_constexpr23 size_t -maximal_binary_length_from_base64(InputPtr input, size_t length) noexcept { - // We process the padding characters ('=') at the end to make sure - // that we return an exact result when the input has no ignorable characters - // (e.g., spaces). - size_t padding = 0; - if (length > 0) { - if (input[length - 1] == '=') { - padding++; - if (length > 1 && input[length - 2] == '=') { - padding++; - } +simdutf_warn_unused simdutf_constexpr23 auto maximal_binary_length_from_base64(InputPtr input, size_t length) noexcept + -> size_t { + // We process the padding characters ('=') at the end to make sure + // that we return an exact result when the input has no ignorable characters + // (e.g., spaces). + size_t padding = 0; + if (length > 0) { + if (input[length - 1] == '=') { + padding++; + if (length > 1 && input[length - 2] == '=') { + padding++; + } + } } - } - // The input is not otherwise processed for ignorable characters or - // validation, so that the function runs in constant time (very fast). In - // practice, base64 inputs without ignorable characters are common and the - // common case are line separated inputs with relatively long lines (e.g., 76 - // characters) which leads this function to a slight (1%) overestimation of - // the output size. - // - // Of course, some inputs might contain an arbitrary number of spaces or - // newlines, which would make this function return a very pessimistic output - // size but systems that produce base64 outputs typically do not do that and - // if they do, they do not care much about minimizing memory usage. - // - // In specialized applications, users may know that their input is line - // separated, which can be checked very quickly by by iterating (e.g., over 76 - // character chunks, looking for the linefeed characters only). We could - // provide a specialized function for that, but it is not clear that the added - // complexity is worth it for us. - // - size_t actual_length = length - padding; - if (actual_length % 4 <= 1) { - return actual_length / 4 * 3; - } - // if we have a valid input, then the remainder must be 2 or 3 adding one or - // two extra bytes. - return actual_length / 4 * 3 + (actual_length % 4) - 1; + // The input is not otherwise processed for ignorable characters or + // validation, so that the function runs in constant time (very fast). In + // practice, base64 inputs without ignorable characters are common and the + // common case are line separated inputs with relatively long lines (e.g., 76 + // characters) which leads this function to a slight (1%) overestimation of + // the output size. + // + // Of course, some inputs might contain an arbitrary number of spaces or + // newlines, which would make this function return a very pessimistic output + // size but systems that produce base64 outputs typically do not do that and + // if they do, they do not care much about minimizing memory usage. + // + // In specialized applications, users may know that their input is line + // separated, which can be checked very quickly by by iterating (e.g., over 76 + // character chunks, looking for the linefeed characters only). We could + // provide a specialized function for that, but it is not clear that the added + // complexity is worth it for us. + // + size_t actualLength = length - padding; + if (actualLength % 4 <= 1) { + return actualLength / 4 * 3; + } + // if we have a valid input, then the remainder must be 2 or 3 adding one or + // two extra bytes. + return (actualLength / 4 * 3) + (actualLength % 4) - 1; } // This function computes the binary length by iterating through the input @@ -10644,176 +9917,151 @@ maximal_binary_length_from_base64(InputPtr input, size_t length) noexcept { // We use a simple check (c > ' ') which is easy to parallelize and matches // SIMD behavior. Only the last few characters are checked for padding '='. template -simdutf_warn_unused simdutf_constexpr23 size_t -binary_length_from_base64(const char_type *input, size_t length) noexcept { - // Count non-whitespace characters (c > ' ') with loop unrolling - size_t count = 0; - for (size_t i = 0; i < length; i++) { - count += (input[i] > ' '); - } - - // Check for padding '=' at the end (at most 2 padding characters) - // Scan backwards, skipping whitespace, to find padding - size_t padding = 0; - size_t pos = length; - // Skip trailing whitespace - while (pos > 0 && padding < 2) { - char_type c = input[--pos]; - if (c == '=') { - padding++; - } else if (c > ' ') { - break; +simdutf_warn_unused simdutf_constexpr23 auto binary_length_from_base64(const char_type* input, size_t length) noexcept + -> size_t { + // Count non-whitespace characters (c > ' ') with loop unrolling + size_t count = 0; + for (size_t i = 0; i < length; i++) { + count += (input[i] > ' '); } - } - return ((count - padding) * 3) / 4; + + // Check for padding '=' at the end (at most 2 padding characters) + // Scan backwards, skipping whitespace, to find padding + size_t padding = 0; + size_t pos = length; + // Skip trailing whitespace + while (pos > 0 && padding < 2) { + char_type c = input[--pos]; + if (c == '=') { + padding++; + } else if (c > ' ') { + break; + } + } + return ((count - padding) * 3) / 4; } template -simdutf_warn_unused simdutf_constexpr23 full_result -base64_to_binary_details_impl( - const char_type *input, size_t length, char *output, base64_options options, - last_chunk_handling_options last_chunk_options) noexcept { - const bool ignore_garbage = - (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - auto ri = simdutf::scalar::base64::find_end(input, length, options); - size_t equallocation = ri.equallocation; - size_t equalsigns = ri.equalsigns; - length = ri.srclen; - size_t full_input_length = ri.full_input_length; - if (length == 0) { - if (!ignore_garbage && equalsigns > 0) { - return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; - } - return {SUCCESS, full_input_length, 0}; - } - full_result r = scalar::base64::base64_tail_decode( - output, input, length, equalsigns, options, last_chunk_options); - r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, - full_input_length, last_chunk_options); - if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && - equalsigns > 0 && !ignore_garbage) { - // additional checks - if ((r.output_count % 3 == 0) || - ((r.output_count % 3) + 1 + equalsigns != 4)) { - return {INVALID_BASE64_CHARACTER, equallocation, r.output_count, true}; - } - } - // When is_partial(last_chunk_options) is true, we must either end with - // the end of the stream (beyond whitespace) or right after a non-ignorable - // character or at the very beginning of the stream. - // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 - if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && - r.input_count < full_input_length) { - // First check if we can extend the input to the end of the stream - while (r.input_count < full_input_length && - base64_ignorable(*(input + r.input_count), options)) { - r.input_count++; - } - // If we are still not at the end of the stream, then we must backtrack - // to the last non-ignorable character. - if (r.input_count < full_input_length) { - while (r.input_count > 0 && - base64_ignorable(*(input + r.input_count - 1), options)) { - r.input_count--; - } +simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_details_impl( + const char_type* input, size_t length, char* output, base64_options options, + last_chunk_handling_options lastChunkOptions) noexcept -> full_result { + const bool ignoreGarbage = (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + auto ri = simdutf::scalar::base64::find_end(input, length, options); + size_t equallocation = ri.equallocation; + size_t equalsigns = ri.equalsigns; + length = ri.srclen; + size_t fullInputLength = ri.full_input_length; + if (length == 0) { + if (!ignoreGarbage && equalsigns > 0) { + return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; + } + return {SUCCESS, fullInputLength, 0}; } - } - return r; + full_result r = scalar::base64::base64_tail_decode(output, input, length, equalsigns, options, lastChunkOptions); + r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, fullInputLength, lastChunkOptions); + if (!is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && equalsigns > 0 && !ignoreGarbage) { + // additional checks + if ((r.outputCount % 3 == 0) || ((r.outputCount % 3) + 1 + equalsigns != 4)) { + return {INVALID_BASE64_CHARACTER, equallocation, r.outputCount, true}; + } + } + // When is_partial(last_chunk_options) is true, we must either end with + // the end of the stream (beyond whitespace) or right after a non-ignorable + // character or at the very beginning of the stream. + // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 + if (is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && r.input_count < fullInputLength) { + // First check if we can extend the input to the end of the stream + while (r.input_count < fullInputLength && base64_ignorable(*(input + r.input_count), options)) { + r.input_count++; + } + // If we are still not at the end of the stream, then we must backtrack + // to the last non-ignorable character. + if (r.input_count < fullInputLength) { + while (r.input_count > 0 && base64_ignorable(*(input + r.input_count - 1), options)) { + r.input_count--; + } + } + } + return r; } template -simdutf_constexpr23 simdutf_warn_unused full_result -base64_to_binary_details_safe_impl( - const char_type *input, size_t length, char *output, size_t outlen, - base64_options options, - last_chunk_handling_options last_chunk_options) noexcept { - const bool ignore_garbage = - (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - auto ri = simdutf::scalar::base64::find_end(input, length, options); - size_t equallocation = ri.equallocation; - size_t equalsigns = ri.equalsigns; - length = ri.srclen; - size_t full_input_length = ri.full_input_length; - if (length == 0) { - if (!ignore_garbage && equalsigns > 0) { - return {INVALID_BASE64_CHARACTER, equallocation, 0}; - } - return {SUCCESS, full_input_length, 0}; - } - full_result r = scalar::base64::base64_tail_decode_safe( - output, outlen, input, length, equalsigns, options, last_chunk_options); - r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, - full_input_length, last_chunk_options); - if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && - equalsigns > 0 && !ignore_garbage) { - // additional checks - if ((r.output_count % 3 == 0) || - ((r.output_count % 3) + 1 + equalsigns != 4)) { - return {INVALID_BASE64_CHARACTER, equallocation, r.output_count}; - } - } - - // When is_partial(last_chunk_options) is true, we must either end with - // the end of the stream (beyond whitespace) or right after a non-ignorable - // character or at the very beginning of the stream. - // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 - if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && - r.input_count < full_input_length) { - // First check if we can extend the input to the end of the stream - while (r.input_count < full_input_length && - base64_ignorable(*(input + r.input_count), options)) { - r.input_count++; - } - // If we are still not at the end of the stream, then we must backtrack - // to the last non-ignorable character. - if (r.input_count < full_input_length) { - while (r.input_count > 0 && - base64_ignorable(*(input + r.input_count - 1), options)) { - r.input_count--; - } +simdutf_constexpr23 simdutf_warn_unused auto base64_to_binary_details_safe_impl( + const char_type* input, size_t length, char* output, size_t outlen, base64_options options, + last_chunk_handling_options lastChunkOptions) noexcept -> full_result { + const bool ignoreGarbage = (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + auto ri = simdutf::scalar::base64::find_end(input, length, options); + size_t equallocation = ri.equallocation; + size_t equalsigns = ri.equalsigns; + length = ri.srclen; + size_t fullInputLength = ri.full_input_length; + if (length == 0) { + if (!ignoreGarbage && equalsigns > 0) { + return {INVALID_BASE64_CHARACTER, equallocation, 0}; + } + return {SUCCESS, fullInputLength, 0}; + } + full_result r = + scalar::base64::base64_tail_decode_safe(output, outlen, input, length, equalsigns, options, lastChunkOptions); + r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, fullInputLength, lastChunkOptions); + if (!is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && equalsigns > 0 && !ignoreGarbage) { + // additional checks + if ((r.outputCount % 3 == 0) || ((r.outputCount % 3) + 1 + equalsigns != 4)) { + return {INVALID_BASE64_CHARACTER, equallocation, r.outputCount}; + } } - } - return r; -} -simdutf_warn_unused simdutf_constexpr23 size_t -base64_length_from_binary(size_t length, base64_options options) noexcept { - // By default, we use padding if we are not using the URL variant. - // This is check with ((options & base64_url) == 0) which returns true if we - // are not using the URL variant. However, we also allow 'inversion' of the - // convention with the base64_reverse_padding option. If the - // base64_reverse_padding option is set, we use padding if we are using the - // URL variant, and we omit it if we are not using the URL variant. This is - // checked with - // ((options & base64_reverse_padding) == base64_reverse_padding). - bool use_padding = - ((options & base64_url) == 0) ^ - ((options & base64_reverse_padding) == base64_reverse_padding); - if (!use_padding) { - return length / 3 * 4 + ((length % 3) ? (length % 3) + 1 : 0); - } - return (length + 2) / 3 * - 4; // We use padding to make the length a multiple of 4. + // When is_partial(last_chunk_options) is true, we must either end with + // the end of the stream (beyond whitespace) or right after a non-ignorable + // character or at the very beginning of the stream. + // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 + if (is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && r.input_count < fullInputLength) { + // First check if we can extend the input to the end of the stream + while (r.input_count < fullInputLength && base64_ignorable(*(input + r.input_count), options)) { + r.input_count++; + } + // If we are still not at the end of the stream, then we must backtrack + // to the last non-ignorable character. + if (r.input_count < fullInputLength) { + while (r.input_count > 0 && base64_ignorable(*(input + r.input_count - 1), options)) { + r.input_count--; + } + } + } + return r; +} + +simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary(size_t length, base64_options options) noexcept + -> size_t { + // By default, we use padding if we are not using the URL variant. + // This is check with ((options & base64_url) == 0) which returns true if we + // are not using the URL variant. However, we also allow 'inversion' of the + // convention with the base64_reverse_padding option. If the + // base64_reverse_padding option is set, we use padding if we are using the + // URL variant, and we omit it if we are not using the URL variant. This is + // checked with + // ((options & base64_reverse_padding) == base64_reverse_padding). + bool usePadding = ((options & base64_url) == 0) ^ ((options & base64ReversePadding) == base64ReversePadding); + if (!usePadding) { + return (length / 3 * 4) + (((length % 3) != 0u) ? (length % 3) + 1 : 0); + } + return (length + 2) / 3 * 4; // We use padding to make the length a multiple of 4. } - -simdutf_warn_unused simdutf_constexpr23 size_t -base64_length_from_binary_with_lines(size_t length, base64_options options, - size_t line_length) noexcept { - if (length == 0) { - return 0; - } - size_t base64_length = - scalar::base64::base64_length_from_binary(length, options); - if (line_length < 4) { - line_length = 4; - } - size_t lines = - (base64_length + line_length - 1) / line_length; // number of lines - return base64_length + lines - 1; + +simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary_with_lines(size_t length, base64_options options, + size_t line_length) noexcept + -> size_t { + if (length == 0) { + return 0; + } + size_t base64Length = scalar::base64::base64_length_from_binary(length, options); + line_length = std::max(line_length, 4); + size_t lines = (base64Length + line_length - 1) / line_length; // number of lines + return base64Length + lines - 1; } // Return the length of the prefix that contains count base64 characters. @@ -10822,76 +10070,73 @@ base64_length_from_binary_with_lines(size_t length, base64_options options, // The function returns (size_t)-1 if there is not enough base64 characters in // the input. template -simdutf_warn_unused size_t prefix_length(size_t count, - simdutf::base64_options options, - const char_type *input, - size_t length) noexcept { - size_t i = 0; - while (i < length && is_ignorable(input[i], options)) { - i++; - } - if (count == 0) { - return i; // duh! - } - for (; i < length; i++) { - if (is_ignorable(input[i], options)) { - continue; +simdutf_warn_unused auto prefix_length(size_t count, simdutf::base64_options options, const char_type* input, + size_t length) noexcept -> size_t { + size_t i = 0; + while (i < length && is_ignorable(input[i], options)) { + i++; } - // We have a base64 character or a padding character. - count--; if (count == 0) { - return i + 1; + return i; // duh! } - } - simdutf_log_assert(false, "You never get here"); + for (; i < length; i++) { + if (is_ignorable(input[i], options)) { + continue; + } + // We have a base64 character or a padding character. + count--; + if (count == 0) { + return i + 1; + } + } + simdutf_log_assert(false, "You never get here"); - return -1; // should never happen + return -1; // should never happen } } // namespace base64 } // unnamed namespace -} // namespace scalar -} // namespace simdutf +} // namespace simdutf::scalar #endif /* end file include/simdutf/scalar/base64.h */ namespace simdutf { -inline std::string_view to_string(base64_options options) { - switch (options) { - case base64_default: - return "base64_default"; - case base64_url: - return "base64_url"; - case base64_reverse_padding: - return "base64_reverse_padding"; - case base64_url_with_padding: - return "base64_url_with_padding"; - case base64_default_accept_garbage: - return "base64_default_accept_garbage"; - case base64_url_accept_garbage: - return "base64_url_accept_garbage"; - case base64_default_or_url: - return "base64_default_or_url"; - case base64_default_or_url_accept_garbage: - return "base64_default_or_url_accept_garbage"; - } - return ""; -} - -inline std::string_view to_string(last_chunk_handling_options options) { - switch (options) { - case loose: - return "loose"; - case strict: - return "strict"; - case stop_before_partial: - return "stop_before_partial"; - case only_full_chunks: - return "only_full_chunks"; - } - return ""; +inline auto to_string(base64_options options) -> std::string_view { + switch (options) { + case base64_default: + return "base64_default"; + case base64_url: + return "base64_url"; + case base64ReversePadding: + return "base64_reverse_padding"; + case base64_url_with_padding: + return "base64_url_with_padding"; + case base64_default_accept_garbage: + return "base64_default_accept_garbage"; + case base64_url_accept_garbage: + return "base64_url_accept_garbage"; + case base64_default_or_url: + return "base64_default_or_url"; + case base64_default_or_url_accept_garbage: + return "base64_default_or_url_accept_garbage"; + } + return ""; +} + +inline auto to_string(last_chunk_handling_options options) -> std::string_view { + switch (options) { + case loose: + return "loose"; + case strict: + return "strict"; + case stop_before_partial: + return "stop_before_partial"; + case only_full_chunks: + return "only_full_chunks"; + } + return ""; } /** @@ -10907,24 +10152,22 @@ inline std::string_view to_string(last_chunk_handling_options options) { * @param length the length of the base64 input in bytes * @return maximum number of binary bytes */ -simdutf_warn_unused size_t -maximal_binary_length_from_base64(const char *input, size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -maximal_binary_length_from_base64( - const detail::input_span_of_byte_like auto &input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::maximal_binary_length_from_base64( - detail::constexpr_cast_ptr(input.data()), input.size()); - } else - #endif - { +simdutf_warn_unused auto maximal_binary_length_from_base64(const char* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto maximal_binary_length_from_base64( + const detail::input_span_of_byte_like auto& input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::maximal_binary_length_from_base64(detail::constexpr_cast_ptr(input.data()), + input.size()); + } else +#endif + { return maximal_binary_length_from_base64( reinterpret_cast(input.data()), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Provide the maximal binary length in bytes given the base64 input. @@ -10940,22 +10183,20 @@ maximal_binary_length_from_base64( * @param length the length of the base64 input in 16-bit units * @return maximal number of binary bytes */ -simdutf_warn_unused size_t maximal_binary_length_from_base64( - const char16_t *input, size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -maximal_binary_length_from_base64(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::maximal_binary_length_from_base64(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto maximal_binary_length_from_base64(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto maximal_binary_length_from_base64(std::span input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::maximal_binary_length_from_base64(input.data(), input.size()); + } else +#endif + { return maximal_binary_length_from_base64(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the binary length from a base64 input. @@ -10971,24 +10212,21 @@ maximal_binary_length_from_base64(std::span input) noexcept { * @param length the length of the base64 input in bytes * @return number of binary bytes */ -simdutf_warn_unused size_t binary_length_from_base64(const char *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -binary_length_from_base64( - const detail::input_span_of_byte_like auto &input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::binary_length_from_base64(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto binary_length_from_base64(const char* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_length_from_base64( + const detail::input_span_of_byte_like auto& input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::binary_length_from_base64(input.data(), input.size()); + } else +#endif + { return binary_length_from_base64( reinterpret_cast(input.data()), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Compute the binary length from a base64 input. @@ -11005,22 +10243,20 @@ binary_length_from_base64( * @param length the length of the base64 input in 16-bit units * @return number of binary bytes */ -simdutf_warn_unused size_t binary_length_from_base64(const char16_t *input, - size_t length) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -binary_length_from_base64(std::span input) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::binary_length_from_base64(input.data(), - input.size()); - } else - #endif - { +simdutf_warn_unused auto binary_length_from_base64(const char16_t* input, size_t length) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused + simdutf_constexpr23 auto binary_length_from_base64(std::span input) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::binary_length_from_base64(input.data(), input.size()); + } else +#endif + { return binary_length_from_base64(input.data(), input.size()); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output. @@ -11076,32 +10312,25 @@ binary_length_from_base64(std::span input) noexcept { * fields error and count) with an error code and either position of the error * (in the input in bytes) if any, or the number of bytes written if successful. */ -simdutf_warn_unused result base64_to_binary( - const char *input, size_t length, char *output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -base64_to_binary( - const detail::input_span_of_byte_like auto &input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::base64_to_binary_details_impl( - input.data(), input.size(), binary_output.data(), options, - last_chunk_options); - } else - #endif - { - return base64_to_binary(reinterpret_cast(input.data()), - input.size(), - reinterpret_cast(binary_output.data()), - options, last_chunk_options); +simdutf_warn_unused auto base64_to_binary(const char* input, size_t length, char* output, + base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = loose) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary( + const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::base64_to_binary_details_impl(input.data(), input.size(), binaryOutput.data(), options, + lastChunkOptions); + } else +#endif + { + return base64_to_binary(reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binaryOutput.data()), options, lastChunkOptions); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Provide the base64 length in bytes given the length of a binary input. @@ -11109,9 +10338,10 @@ base64_to_binary( * @param length the length of the input in bytes * @return number of base64 bytes */ -inline simdutf_warn_unused simdutf_constexpr23 size_t base64_length_from_binary( - size_t length, base64_options options = base64_default) noexcept { - return scalar::base64::base64_length_from_binary(length, options); +simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary(size_t length, + base64_options options = base64_default) noexcept + -> size_t { + return scalar::base64::base64_length_from_binary(length, options); } /** @@ -11123,12 +10353,9 @@ inline simdutf_warn_unused simdutf_constexpr23 size_t base64_length_from_binary( * interpreted as 4), * @return number of base64 bytes */ -inline simdutf_warn_unused simdutf_constexpr23 size_t -base64_length_from_binary_with_lines( - size_t length, base64_options options = base64_default, - size_t line_length = default_line_length) noexcept { - return scalar::base64::base64_length_from_binary_with_lines(length, options, - line_length); +simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary_with_lines( + size_t length, base64_options options = base64_default, size_t lineLength = defaultLineLength) noexcept -> size_t { + return scalar::base64::base64_length_from_binary_with_lines(length, options, lineLength); } /** @@ -11152,26 +10379,23 @@ base64_length_from_binary_with_lines( * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ -size_t binary_to_base64(const char *input, size_t length, char *output, - base64_options options = base64_default) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -binary_to_base64(const detail::input_span_of_byte_like auto &input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::tail_encode_base64( - binary_output.data(), input.data(), input.size(), options); - } else - #endif - { - return binary_to_base64( - reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binary_output.data()), options); +auto binary_to_base64(const char* input, size_t length, char* output, base64_options options = base64_default) noexcept + -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_to_base64( + const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::tail_encode_base64(binaryOutput.data(), input.data(), input.size(), options); + } else +#endif + { + return binary_to_base64(reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binaryOutput.data()), options); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert a binary input to a base64 output with line breaks. @@ -11197,32 +10421,27 @@ binary_to_base64(const detail::input_span_of_byte_like auto &input, * @return number of written bytes, will be equal to * base64_length_from_binary_with_lines(length, options) */ -size_t -binary_to_base64_with_lines(const char *input, size_t length, char *output, - size_t line_length = simdutf::default_line_length, - base64_options options = base64_default) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t -binary_to_base64_with_lines( - const detail::input_span_of_byte_like auto &input, - detail::output_span_of_byte_like auto &&binary_output, - size_t line_length = simdutf::default_line_length, - base64_options options = base64_default) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::tail_encode_base64_impl( - binary_output.data(), input.data(), input.size(), options, line_length); - } else - #endif - { - return binary_to_base64_with_lines( - reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binary_output.data()), line_length, options); +auto binary_to_base64_with_lines(const char* input, size_t length, char* output, + size_t lineLength = simdutf::defaultLineLength, + base64_options options = base64_default) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_to_base64_with_lines( + const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, + size_t lineLength = simdutf::defaultLineLength, base64_options options = base64_default) noexcept -> size_t { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::tail_encode_base64_impl(binaryOutput.data(), input.data(), input.size(), options, + lineLength); + } else +#endif + { + return binary_to_base64_with_lines(reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binaryOutput.data()), lineLength, options); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN - #if SIMDUTF_ATOMIC_REF +#if SIMDUTF_ATOMIC_REF /** * Convert a binary input to a base64 output, using atomic accesses. * This function comes with a potentially significant performance @@ -11264,20 +10483,17 @@ binary_to_base64_with_lines( * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ -size_t -atomic_binary_to_base64(const char *input, size_t length, char *output, - base64_options options = base64_default) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused size_t -atomic_binary_to_base64(const detail::input_span_of_byte_like auto &input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default) noexcept { - return atomic_binary_to_base64( - reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binary_output.data()), options); +auto atomic_binary_to_base64(const char* input, size_t length, char* output, + base64_options options = base64_default) noexcept -> size_t; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused auto atomic_binary_to_base64( + const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default) noexcept -> size_t { + return atomic_binary_to_base64(reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binaryOutput.data()), options); } - #endif // SIMDUTF_SPAN - #endif // SIMDUTF_ATOMIC_REF +#endif // SIMDUTF_SPAN +#endif // SIMDUTF_ATOMIC_REF /** * Convert a base64 input to a binary output. @@ -11335,32 +10551,25 @@ atomic_binary_to_base64(const detail::input_span_of_byte_like auto &input, * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number * of bytes written if successful. */ -simdutf_warn_unused result -base64_to_binary(const char16_t *input, size_t length, char *output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result -base64_to_binary( - std::span input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::base64_to_binary_details_impl( - input.data(), input.size(), binary_output.data(), options, - last_chunk_options); - } else - #endif - { - return base64_to_binary(input.data(), input.size(), - reinterpret_cast(binary_output.data()), - options, last_chunk_options); +simdutf_warn_unused auto base64_to_binary( + const char16_t* input, size_t length, char* output, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) noexcept -> result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary( + std::span input, detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose) noexcept -> result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::base64_to_binary_details_impl(input.data(), input.size(), binaryOutput.data(), options, + lastChunkOptions); + } else +#endif + { + return base64_to_binary(input.data(), input.size(), reinterpret_cast(binaryOutput.data()), options, + lastChunkOptions); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output while returning more details @@ -11409,33 +10618,26 @@ base64_to_binary( * @return a full_result struct (of type simdutf::full_result containing the * three fields error, input_count and output_count). */ -simdutf_warn_unused full_result -base64_to_binary_details(const char *input, size_t length, char *output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result -base64_to_binary_details( - const detail::input_span_of_byte_like auto &input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::base64_to_binary_details_impl( - input.data(), input.size(), binary_output.data(), options, - last_chunk_options); - } else - #endif - { - return base64_to_binary_details( - reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binary_output.data()), options, - last_chunk_options); +simdutf_warn_unused auto base64_to_binary_details( + const char* input, size_t length, char* output, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) noexcept -> full_result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_details( + const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose) noexcept + -> full_result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::base64_to_binary_details_impl(input.data(), input.size(), binaryOutput.data(), options, + lastChunkOptions); + } else +#endif + { + return base64_to_binary_details(reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binaryOutput.data()), options, lastChunkOptions); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output while returning more details @@ -11485,33 +10687,26 @@ base64_to_binary_details( * @return a full_result struct (of type simdutf::full_result containing the * three fields error, input_count and output_count). */ -simdutf_warn_unused full_result -base64_to_binary_details(const char16_t *input, size_t length, char *output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose) noexcept; - #if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result -base64_to_binary_details( - std::span input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose) noexcept { - #if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::base64_to_binary_details_impl( - input.data(), input.size(), binary_output.data(), options, - last_chunk_options); - } else - #endif - { - return base64_to_binary_details( - input.data(), input.size(), - reinterpret_cast(binary_output.data()), options, - last_chunk_options); +simdutf_warn_unused auto base64_to_binary_details( + const char16_t* input, size_t length, char* output, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) noexcept -> full_result; +#if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_details( + std::span input, detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose) noexcept + -> full_result { +#if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::base64_to_binary_details_impl(input.data(), input.size(), binaryOutput.data(), options, + lastChunkOptions); + } else +#endif + { + return base64_to_binary_details(input.data(), input.size(), reinterpret_cast(binaryOutput.data()), + options, lastChunkOptions); } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN /** * Check if a character is an ignorable base64 character. @@ -11523,14 +10718,13 @@ base64_to_binary_details( * @return true if the character is an ignorable base64 character, false * otherwise. */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool -base64_ignorable(char input, base64_options options = base64_default) noexcept { - return scalar::base64::is_ignorable(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_ignorable( + char input, base64_options options = base64_default) noexcept -> bool { + return scalar::base64::is_ignorable(input, options); } -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool -base64_ignorable(char16_t input, - base64_options options = base64_default) noexcept { - return scalar::base64::is_ignorable(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_ignorable( + char16_t input, base64_options options = base64_default) noexcept -> bool { + return scalar::base64::is_ignorable(input, options); } /** @@ -11544,13 +10738,13 @@ base64_ignorable(char16_t input, * @param options the base64 options to use, is base64_default by default. * @return true if the character is a base64 character, false otherwise. */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool -base64_valid(char input, base64_options options = base64_default) noexcept { - return scalar::base64::is_base64(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid( + char input, base64_options options = base64_default) noexcept -> bool { + return scalar::base64::is_base64(input, options); } -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool -base64_valid(char16_t input, base64_options options = base64_default) noexcept { - return scalar::base64::is_base64(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid( + char16_t input, base64_options options = base64_default) noexcept -> bool { + return scalar::base64::is_base64(input, options); } /** @@ -11562,15 +10756,13 @@ base64_valid(char16_t input, base64_options options = base64_default) noexcept { * @param options the base64 options to use, is base64_default by default. * @return true if the character is a base64 character, false otherwise. */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool -base64_valid_or_padding(char input, - base64_options options = base64_default) noexcept { - return scalar::base64::is_base64_or_padding(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid_or_padding( + char input, base64_options options = base64_default) noexcept -> bool { + return scalar::base64::is_base64_or_padding(input, options); } -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool -base64_valid_or_padding(char16_t input, - base64_options options = base64_default) noexcept { - return scalar::base64::is_base64_or_padding(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid_or_padding( + char16_t input, base64_options options = base64_default) noexcept -> bool { + return scalar::base64::is_base64_or_padding(input, options); } /** @@ -11640,23 +10832,19 @@ base64_valid_or_padding(char16_t input, * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number * of units processed if successful. */ -simdutf_warn_unused result -base64_to_binary_safe(const char *input, size_t length, char *output, - size_t &outlen, base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose, - bool decode_up_to_bad_char = false) noexcept; +simdutf_warn_unused auto base64_to_binary_safe( + const char* input, size_t length, char* output, size_t& outlen, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose, + bool decodeUpToBadChar = false) noexcept -> result; // the span overload has moved to the bottom of the file -simdutf_warn_unused result -base64_to_binary_safe(const char16_t *input, size_t length, char *output, - size_t &outlen, base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose, - bool decode_up_to_bad_char = false) noexcept; - // span overload moved to bottom of file +simdutf_warn_unused auto base64_to_binary_safe( + const char16_t* input, size_t length, char* output, size_t& outlen, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose, + bool decodeUpToBadChar = false) noexcept -> result; +// span overload moved to bottom of file - #if SIMDUTF_ATOMIC_REF +#if SIMDUTF_ATOMIC_REF /** * Convert a base64 input to a binary output with a size limit and using atomic * operations. @@ -11696,57 +10884,48 @@ base64_to_binary_safe(const char16_t *input, size_t length, char *output, * @return a result struct with an error code and count indicating error * position or success */ -simdutf_warn_unused result atomic_base64_to_binary_safe( - const char *input, size_t length, char *output, size_t &outlen, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose, - bool decode_up_to_bad_char = false) noexcept; -simdutf_warn_unused result atomic_base64_to_binary_safe( - const char16_t *input, size_t length, char *output, size_t &outlen, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose, - bool decode_up_to_bad_char = false) noexcept; - #if SIMDUTF_SPAN +simdutf_warn_unused auto atomic_base64_to_binary_safe( + const char* input, size_t length, char* output, size_t& outlen, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose, + bool decodeUpToBadChar = false) noexcept -> result; +simdutf_warn_unused auto atomic_base64_to_binary_safe(const char16_t* input, size_t length, char* output, + size_t& outlen, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = loose, + bool decodeUpToBadChar = false) noexcept -> result; +#if SIMDUTF_SPAN /** * @brief span overload * @return a tuple of result and outlen */ -simdutf_really_inline simdutf_warn_unused std::tuple -atomic_base64_to_binary_safe( - const detail::input_span_of_byte_like auto &binary_input, - detail::output_span_of_byte_like auto &&output, +simdutf_really_inline simdutf_warn_unused auto atomic_base64_to_binary_safe( + const detail::input_span_of_byte_like auto& binaryInput, detail::output_span_of_byte_like auto&& output, base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose, - bool decode_up_to_bad_char = false) noexcept { - size_t outlen = output.size(); - auto ret = atomic_base64_to_binary_safe( - reinterpret_cast(binary_input.data()), binary_input.size(), - reinterpret_cast(output.data()), outlen, options, - last_chunk_options, decode_up_to_bad_char); - return {ret, outlen}; + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose, + bool decodeUpToBadChar = false) noexcept -> std::tuple { + size_t outlen = output.size(); + auto ret = atomic_base64_to_binary_safe(reinterpret_cast(binaryInput.data()), binaryInput.size(), + reinterpret_cast(output.data()), outlen, options, lastChunkOptions, + decodeUpToBadChar); + return {ret, outlen}; } /** * @brief span overload * @return a tuple of result and outlen */ -simdutf_warn_unused std::tuple -atomic_base64_to_binary_safe( - std::span base64_input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose, - bool decode_up_to_bad_char = false) noexcept { - size_t outlen = binary_output.size(); - auto ret = atomic_base64_to_binary_safe( - base64_input.data(), base64_input.size(), - reinterpret_cast(binary_output.data()), outlen, options, - last_chunk_options, decode_up_to_bad_char); - return {ret, outlen}; -} - #endif // SIMDUTF_SPAN - #endif // SIMDUTF_ATOMIC_REF +simdutf_warn_unused auto atomic_base64_to_binary_safe(std::span base64Input, + detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = loose, + bool decodeUpToBadChar = false) noexcept + -> std::tuple { + size_t outlen = binaryOutput.size(); + auto ret = atomic_base64_to_binary_safe(base64Input.data(), base64Input.size(), + reinterpret_cast(binaryOutput.data()), outlen, options, + lastChunkOptions, decodeUpToBadChar); + return {ret, outlen}; +} +#endif // SIMDUTF_SPAN +#endif // SIMDUTF_ATOMIC_REF #endif // SIMDUTF_FEATURE_BASE64 @@ -11768,7 +10947,9 @@ class implementation { * * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" */ - virtual std::string_view name() const noexcept { return _name; } + [[nodiscard]] virtual auto name() const noexcept -> std::string_view { + return _name; + } /** * The description of this implementation. @@ -11779,7 +10960,9 @@ class implementation { * * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" */ - virtual std::string_view description() const noexcept { return _description; } + [[nodiscard]] virtual auto description() const noexcept -> std::string_view { + return _description; + } /** * The instruction sets this implementation is compiled against @@ -11790,7 +10973,7 @@ class implementation { * @return true if the implementation can be safely used on the current system * (determined at runtime) */ - bool supported_by_runtime_system() const; + [[nodiscard]] auto supported_by_runtime_system() const -> bool; #if SIMDUTF_FEATURE_DETECT_ENCODING /** @@ -11799,17 +10982,15 @@ class implementation { * @param length the length of the string in bytes. * @return the encoding type detected */ - virtual encoding_type autodetect_encoding(const char *input, - size_t length) const noexcept; + virtual auto autodetect_encoding(const char* input, size_t length) const noexcept -> encoding_type; - /** + /** * This function will try to detect the possible encodings in one pass * @param input the string to identify * @param length the length of the string in bytes. * @return the encoding type detected */ - virtual int detect_encodings(const char *input, - size_t length) const noexcept = 0; + virtual auto detect_encodings(const char* input, size_t length) const noexcept -> int = 0; #endif // SIMDUTF_FEATURE_DETECT_ENCODING /** @@ -11819,9 +11000,9 @@ class implementation { * * @return a mask of all required `internal::instruction_set::` values */ - virtual uint32_t required_instruction_sets() const { - return _required_instruction_sets; - } + [[nodiscard]] virtual auto required_instruction_sets() const -> uint32_t { + return _requiredInstructionSets; + } #if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING /** @@ -11833,8 +11014,7 @@ class implementation { * @param len the length of the string in bytes. * @return true if and only if the string is valid UTF-8. */ - simdutf_warn_unused virtual bool validate_utf8(const char *buf, - size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf8(const char* buf, size_t len) const noexcept -> bool = 0; #endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 @@ -11850,8 +11030,8 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual result - validate_utf8_with_errors(const char *buf, size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf8_with_errors(const char* buf, size_t len) const noexcept + -> result = 0; #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_ASCII @@ -11864,10 +11044,9 @@ class implementation { * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ - simdutf_warn_unused virtual bool - validate_ascii(const char *buf, size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_ascii(const char* buf, size_t len) const noexcept -> bool = 0; - /** + /** * Validate the ASCII string and stop on error. * * Overridden by each implementation. @@ -11879,8 +11058,8 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual result - validate_ascii_with_errors(const char *buf, size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_ascii_with_errors(const char* buf, size_t len) const noexcept + -> result = 0; #endif // SIMDUTF_FEATURE_ASCII @@ -11896,10 +11075,10 @@ class implementation { * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ - simdutf_warn_unused virtual bool - validate_utf16be_as_ascii(const char16_t *buf, size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf16be_as_ascii(const char16_t* buf, size_t len) const noexcept + -> bool = 0; - /** + /** * Validate the ASCII string as a UTF-16LE sequence. * An UTF-16 sequence is considered an ASCII sequence * if it could be converted to an ASCII string losslessly. @@ -11910,8 +11089,8 @@ class implementation { * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ - simdutf_warn_unused virtual bool - validate_utf16le_as_ascii(const char16_t *buf, size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf16le_as_ascii(const char16_t* buf, size_t len) const noexcept + -> bool = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING @@ -11929,8 +11108,7 @@ class implementation { * (char16_t). * @return true if and only if the string is valid UTF-16LE. */ - simdutf_warn_unused virtual bool - validate_utf16le(const char16_t *buf, size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf16le(const char16_t* buf, size_t len) const noexcept -> bool = 0; #endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF16 @@ -11948,10 +11126,9 @@ class implementation { * (char16_t). * @return true if and only if the string is valid UTF-16BE. */ - simdutf_warn_unused virtual bool - validate_utf16be(const char16_t *buf, size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf16be(const char16_t* buf, size_t len) const noexcept -> bool = 0; - /** + /** * Validate the UTF-16LE string and stop on error. It might be faster than * validate_utf16le when an error is expected to occur early. * @@ -11967,11 +11144,10 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual result - validate_utf16le_with_errors(const char16_t *buf, - size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf16le_with_errors(const char16_t* buf, size_t len) const noexcept + -> result = 0; - /** + /** * Validate the UTF-16BE string and stop on error. It might be faster than * validate_utf16be when an error is expected to occur early. * @@ -11987,10 +11163,9 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual result - validate_utf16be_with_errors(const char16_t *buf, - size_t len) const noexcept = 0; - /** + simdutf_warn_unused virtual auto validate_utf16be_with_errors(const char16_t* buf, size_t len) const noexcept + -> result = 0; + /** * Copies the UTF-16LE string while replacing mismatched surrogates with the * Unicode replacement character U+FFFD. We allow the input and output to be * the same buffer so that the correction is done in-place. @@ -12002,9 +11177,8 @@ class implementation { * (char16_t). * @param output the output buffer. */ - virtual void to_well_formed_utf16le(const char16_t *input, size_t len, - char16_t *output) const noexcept = 0; - /** + virtual void to_well_formed_utf16le(const char16_t* input, size_t len, char16_t* output) const noexcept = 0; + /** * Copies the UTF-16BE string while replacing mismatched surrogates with the * Unicode replacement character U+FFFD. We allow the input and output to be * the same buffer so that the correction is done in-place. @@ -12016,8 +11190,7 @@ class implementation { * (char16_t). * @param output the output buffer. */ - virtual void to_well_formed_utf16be(const char16_t *input, size_t len, - char16_t *output) const noexcept = 0; + virtual void to_well_formed_utf16be(const char16_t* input, size_t len, char16_t* output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING @@ -12033,8 +11206,7 @@ class implementation { * (char32_t). * @return true if and only if the string is valid UTF-32. */ - simdutf_warn_unused virtual bool - validate_utf32(const char32_t *buf, size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf32(const char32_t* buf, size_t len) const noexcept -> bool = 0; #endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF32 @@ -12053,9 +11225,8 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual result - validate_utf32_with_errors(const char32_t *buf, - size_t len) const noexcept = 0; + simdutf_warn_unused virtual auto validate_utf32_with_errors(const char32_t* buf, size_t len) const noexcept + -> result = 0; #endif // SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -12069,9 +11240,8 @@ class implementation { * @param utf8_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_latin1_to_utf8(const char *input, size_t length, - char *utf8_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_latin1_to_utf8(const char* input, size_t length, + char* utf8Output) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -12085,11 +11255,10 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_latin1_to_utf16le(const char *input, size_t length, - char16_t *utf16_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_latin1_to_utf16le(const char* input, size_t length, + char16_t* utf16Output) const noexcept -> size_t = 0; - /** + /** * Convert Latin1 string into UTF-16BE string. * * This function is suitable to work with inputs from untrusted sources. @@ -12099,9 +11268,8 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_latin1_to_utf16be(const char *input, size_t length, - char16_t *utf16_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_latin1_to_utf16be(const char* input, size_t length, + char16_t* utf16Output) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12115,9 +11283,8 @@ class implementation { * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_latin1_to_utf32(const char *input, size_t length, - char32_t *utf32_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_latin1_to_utf32(const char* input, size_t length, + char32_t* utf32Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -12133,11 +11300,10 @@ class implementation { * @return the number of written char; 0 if the input was not valid UTF-8 * string or if it cannot be represented as Latin1 */ - simdutf_warn_unused virtual size_t - convert_utf8_to_latin1(const char *input, size_t length, - char *latin1_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf8_to_latin1(const char* input, size_t length, + char* latin1Output) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-8 string into latin1 string with errors. * If the string cannot be represented as Latin1, an error * code is returned. @@ -12153,11 +11319,11 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual result - convert_utf8_to_latin1_with_errors(const char *input, size_t length, - char *latin1_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf8_to_latin1_with_errors(const char* input, size_t length, + char* latin1Output) const noexcept + -> result = 0; - /** + /** * Convert valid UTF-8 string into latin1 string. * * This function assumes that the input string is valid UTF-8 and that it can @@ -12176,9 +11342,8 @@ class implementation { * @return the number of written char; 0 if the input was not valid UTF-8 * string */ - simdutf_warn_unused virtual size_t - convert_valid_utf8_to_latin1(const char *input, size_t length, - char *latin1_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf8_to_latin1(const char* input, size_t length, + char* latin1Output) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -12194,11 +11359,10 @@ class implementation { * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ - simdutf_warn_unused virtual size_t - convert_utf8_to_utf16le(const char *input, size_t length, - char16_t *utf16_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf8_to_utf16le(const char* input, size_t length, + char16_t* utf16Output) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-8 string into UTF-16BE string. * * During the conversion also validation of the input string is done. @@ -12210,11 +11374,10 @@ class implementation { * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ - simdutf_warn_unused virtual size_t - convert_utf8_to_utf16be(const char *input, size_t length, - char16_t *utf16_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf8_to_utf16be(const char* input, size_t length, + char16_t* utf16Output) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-8 string into UTF-16LE string and stop on * error. * @@ -12229,11 +11392,11 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual result convert_utf8_to_utf16le_with_errors( - const char *input, size_t length, - char16_t *utf16_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf8_to_utf16le_with_errors(const char* input, size_t length, + char16_t* utf16Output) const noexcept + -> result = 0; - /** + /** * Convert possibly broken UTF-8 string into UTF-16BE string and stop on * error. * @@ -12248,10 +11411,10 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual result convert_utf8_to_utf16be_with_errors( - const char *input, size_t length, - char16_t *utf16_output) const noexcept = 0; - /** + simdutf_warn_unused virtual auto convert_utf8_to_utf16be_with_errors(const char* input, size_t length, + char16_t* utf16Output) const noexcept + -> result = 0; + /** * Compute the number of bytes that this UTF-16LE string would require in * UTF-8 format even when the UTF-16LE content contains mismatched * surrogates that have to be replaced by the replacement character (0xFFFD). @@ -12270,10 +11433,11 @@ class implementation { * contains no surrogate, is in the Basic Multilingual Plane, and is * necessarily valid. */ - virtual simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( - const char16_t *input, size_t length) const noexcept = 0; + virtual simdutf_warn_unused auto utf8_length_from_utf16le_with_replacement(const char16_t* input, + size_t length) const noexcept + -> result = 0; - /** + /** * Compute the number of bytes that this UTF-16BE string would require in * UTF-8 format even when the UTF-16BE content contains mismatched * surrogates that have to be replaced by the replacement character (0xFFFD). @@ -12292,8 +11456,9 @@ class implementation { * contains no surrogate, is in the Basic Multilingual Plane, and is * necessarily valid. */ - virtual simdutf_warn_unused result utf8_length_from_utf16be_with_replacement( - const char16_t *input, size_t length) const noexcept = 0; + virtual simdutf_warn_unused auto utf8_length_from_utf16be_with_replacement(const char16_t* input, + size_t length) const noexcept + -> result = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -12310,11 +11475,10 @@ class implementation { * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ - simdutf_warn_unused virtual size_t - convert_utf8_to_utf32(const char *input, size_t length, - char32_t *utf32_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf8_to_utf32(const char* input, size_t length, + char32_t* utf32Output) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-8 string into UTF-32 string and stop on error. * * During the conversion also validation of the input string is done. @@ -12328,9 +11492,9 @@ class implementation { * (in the input in code units) if any, or the number of char32_t written if * successful. */ - simdutf_warn_unused virtual result - convert_utf8_to_utf32_with_errors(const char *input, size_t length, - char32_t *utf32_output) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf8_to_utf32_with_errors(const char* input, size_t length, + char32_t* utf32Output) const noexcept + -> result = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -12344,11 +11508,10 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ - simdutf_warn_unused virtual size_t - convert_valid_utf8_to_utf16le(const char *input, size_t length, - char16_t *utf16_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf8_to_utf16le(const char* input, size_t length, + char16_t* utf16Buffer) const noexcept -> size_t = 0; - /** + /** * Convert valid UTF-8 string into UTF-16BE string. * * This function assumes that the input string is valid UTF-8. @@ -12358,9 +11521,8 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ - simdutf_warn_unused virtual size_t - convert_valid_utf8_to_utf16be(const char *input, size_t length, - char16_t *utf16_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf8_to_utf16be(const char* input, size_t length, + char16_t* utf16Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -12374,9 +11536,8 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t */ - simdutf_warn_unused virtual size_t - convert_valid_utf8_to_utf32(const char *input, size_t length, - char32_t *utf32_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf8_to_utf32(const char* input, size_t length, + char32_t* utf32Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -12392,8 +11553,8 @@ class implementation { * @return the number of char16_t code units required to encode the UTF-8 * string as UTF-16LE */ - simdutf_warn_unused virtual size_t - utf16_length_from_utf8(const char *input, size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf16_length_from_utf8(const char* input, size_t length) const noexcept + -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -12411,8 +11572,8 @@ class implementation { * @return the number of char32_t code units required to encode the UTF-8 * string as UTF-32 */ - simdutf_warn_unused virtual size_t - utf32_length_from_utf8(const char *input, size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf32_length_from_utf8(const char* input, size_t length) const noexcept + -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -12432,11 +11593,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16LE * string or if it cannot be represented as Latin1 */ - simdutf_warn_unused virtual size_t - convert_utf16le_to_latin1(const char16_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16le_to_latin1(const char16_t* input, size_t length, + char* latin1Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-16BE string into Latin1 string. * * During the conversion also validation of the input string is done. @@ -12452,11 +11612,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16BE * string or if it cannot be represented as Latin1 */ - simdutf_warn_unused virtual size_t - convert_utf16be_to_latin1(const char16_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16be_to_latin1(const char16_t* input, size_t length, + char* latin1Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-16LE string into Latin1 string. * If the string cannot be represented as Latin1, an error * is returned. @@ -12475,11 +11634,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual result - convert_utf16le_to_latin1_with_errors(const char16_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16le_to_latin1_with_errors(const char16_t* input, size_t length, + char* latin1Buffer) const noexcept + -> result = 0; - /** + /** * Convert possibly broken UTF-16BE string into Latin1 string. * If the string cannot be represented as Latin1, an error * is returned. @@ -12498,11 +11657,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual result - convert_utf16be_to_latin1_with_errors(const char16_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16be_to_latin1_with_errors(const char16_t* input, size_t length, + char* latin1Buffer) const noexcept + -> result = 0; - /** + /** * Convert valid UTF-16LE string into Latin1 string. * * This function assumes that the input string is valid UTF-L16LE and that it @@ -12522,11 +11681,10 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf16le_to_latin1(const char16_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf16le_to_latin1(const char16_t* input, size_t length, + char* latin1Buffer) const noexcept -> size_t = 0; - /** + /** * Convert valid UTF-16BE string into Latin1 string. * * This function assumes that the input string is valid UTF16-BE and that it @@ -12546,9 +11704,8 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf16be_to_latin1(const char16_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf16be_to_latin1(const char16_t* input, size_t length, + char* latin1Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -12567,11 +11724,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ - simdutf_warn_unused virtual size_t - convert_utf16le_to_utf8(const char16_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16le_to_utf8(const char16_t* input, size_t length, + char* utf8Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-8 string. * * During the conversion also validation of the input string is done. @@ -12586,11 +11742,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16BE * string */ - simdutf_warn_unused virtual size_t - convert_utf16be_to_utf8(const char16_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16be_to_utf8(const char16_t* input, size_t length, + char* utf8Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-16LE string into UTF-8 string and stop on * error. * @@ -12608,11 +11763,10 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual result - convert_utf16le_to_utf8_with_errors(const char16_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16le_to_utf8_with_errors(const char16_t* input, size_t length, + char* utf8Buffer) const noexcept -> result = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-8 string and stop on * error. * @@ -12630,11 +11784,10 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual result - convert_utf16be_to_utf8_with_errors(const char16_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16be_to_utf8_with_errors(const char16_t* input, size_t length, + char* utf8Buffer) const noexcept -> result = 0; - /** + /** * Convert possibly broken UTF-16LE string into UTF-8 string, replacing * unpaired surrogates with the Unicode replacement character U+FFFD. * @@ -12649,11 +11802,11 @@ class implementation { * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ - simdutf_warn_unused virtual size_t convert_utf16le_to_utf8_with_replacement( - const char16_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16le_to_utf8_with_replacement(const char16_t* input, size_t length, + char* utf8Buffer) const noexcept + -> size_t = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-8 string, replacing * unpaired surrogates with the Unicode replacement character U+FFFD. * @@ -12668,11 +11821,11 @@ class implementation { * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ - simdutf_warn_unused virtual size_t convert_utf16be_to_utf8_with_replacement( - const char16_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16be_to_utf8_with_replacement(const char16_t* input, size_t length, + char* utf8Buffer) const noexcept + -> size_t = 0; - /** + /** * Convert valid UTF-16LE string into UTF-8 string. * * This function assumes that the input string is valid UTF-16LE. @@ -12686,11 +11839,10 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf16le_to_utf8(const char16_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf16le_to_utf8(const char16_t* input, size_t length, + char* utf8Buffer) const noexcept -> size_t = 0; - /** + /** * Convert valid UTF-16BE string into UTF-8 string. * * This function assumes that the input string is valid UTF-16BE. @@ -12704,9 +11856,8 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf16be_to_utf8(const char16_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf16be_to_utf8(const char16_t* input, size_t length, + char* utf8Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -12725,11 +11876,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ - simdutf_warn_unused virtual size_t - convert_utf16le_to_utf32(const char16_t *input, size_t length, - char32_t *utf32_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16le_to_utf32(const char16_t* input, size_t length, + char32_t* utf32Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-32 string. * * During the conversion also validation of the input string is done. @@ -12744,11 +11894,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16BE * string */ - simdutf_warn_unused virtual size_t - convert_utf16be_to_utf32(const char16_t *input, size_t length, - char32_t *utf32_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16be_to_utf32(const char16_t* input, size_t length, + char32_t* utf32Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-16LE string into UTF-32 string and stop on * error. * @@ -12766,11 +11915,11 @@ class implementation { * (in the input in code units) if any, or the number of char32_t written if * successful. */ - simdutf_warn_unused virtual result convert_utf16le_to_utf32_with_errors( - const char16_t *input, size_t length, - char32_t *utf32_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16le_to_utf32_with_errors(const char16_t* input, size_t length, + char32_t* utf32Buffer) const noexcept + -> result = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-32 string and stop on * error. * @@ -12788,11 +11937,11 @@ class implementation { * (in the input in code units) if any, or the number of char32_t written if * successful. */ - simdutf_warn_unused virtual result convert_utf16be_to_utf32_with_errors( - const char16_t *input, size_t length, - char32_t *utf32_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf16be_to_utf32_with_errors(const char16_t* input, size_t length, + char32_t* utf32Buffer) const noexcept + -> result = 0; - /** + /** * Convert valid UTF-16LE string into UTF-32 string. * * This function assumes that the input string is valid UTF-16LE. @@ -12806,11 +11955,10 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf16le_to_utf32(const char16_t *input, size_t length, - char32_t *utf32_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf16le_to_utf32(const char16_t* input, size_t length, + char32_t* utf32Buffer) const noexcept -> size_t = 0; - /** + /** * Convert valid UTF-16LE string into UTF-32BE string. * * This function assumes that the input string is valid UTF-16BE. @@ -12824,9 +11972,8 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf16be_to_utf32(const char16_t *input, size_t length, - char32_t *utf32_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf16be_to_utf32(const char16_t* input, size_t length, + char32_t* utf32Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -12844,11 +11991,10 @@ class implementation { * (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ - simdutf_warn_unused virtual size_t - utf8_length_from_utf16le(const char16_t *input, - size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf8_length_from_utf16le(const char16_t* input, size_t length) const noexcept + -> size_t = 0; - /** + /** * Compute the number of bytes that this UTF-16BE string would require in * UTF-8 format. * @@ -12862,9 +12008,8 @@ class implementation { * (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-8 */ - simdutf_warn_unused virtual size_t - utf8_length_from_utf16be(const char16_t *input, - size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf8_length_from_utf16be(const char16_t* input, size_t length) const noexcept + -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12884,9 +12029,8 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-32 * string */ - simdutf_warn_unused virtual size_t - convert_utf32_to_latin1(const char32_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf32_to_latin1(const char32_t* input, size_t length, + char* latin1Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12909,11 +12053,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual result - convert_utf32_to_latin1_with_errors(const char32_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf32_to_latin1_with_errors(const char32_t* input, size_t length, + char* latin1Buffer) const noexcept + -> result = 0; - /** + /** * Convert valid UTF-32 string into Latin1 string. * * This function assumes that the input string is valid UTF-32 and can be @@ -12933,9 +12077,8 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf32_to_latin1(const char32_t *input, size_t length, - char *latin1_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf32_to_latin1(const char32_t* input, size_t length, + char* latin1Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -12954,11 +12097,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-32 * string */ - simdutf_warn_unused virtual size_t - convert_utf32_to_utf8(const char32_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf32_to_utf8(const char32_t* input, size_t length, + char* utf8Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-32 string into UTF-8 string and stop on error. * * During the conversion also validation of the input string is done. @@ -12975,11 +12117,10 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual result - convert_utf32_to_utf8_with_errors(const char32_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf32_to_utf8_with_errors(const char32_t* input, size_t length, + char* utf8Buffer) const noexcept -> result = 0; - /** + /** * Convert valid UTF-32 string into UTF-8 string. * * This function assumes that the input string is valid UTF-32. @@ -12993,9 +12134,8 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf32_to_utf8(const char32_t *input, size_t length, - char *utf8_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf32_to_utf8(const char32_t* input, size_t length, + char* utf8Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -13009,10 +12149,9 @@ class implementation { * (char16_t) * @return the number of bytes required to encode the UTF-16 string as Latin1 */ - simdutf_warn_unused virtual size_t - utf16_length_from_latin1(size_t length) const noexcept { - return length; - } + simdutf_warn_unused virtual auto utf16_length_from_latin1(size_t length) const noexcept -> size_t { + return length; + } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -13031,11 +12170,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-32 * string */ - simdutf_warn_unused virtual size_t - convert_utf32_to_utf16le(const char32_t *input, size_t length, - char16_t *utf16_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf32_to_utf16le(const char32_t* input, size_t length, + char16_t* utf16Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-32 string into UTF-16BE string. * * During the conversion also validation of the input string is done. @@ -13050,11 +12188,10 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-32 * string */ - simdutf_warn_unused virtual size_t - convert_utf32_to_utf16be(const char32_t *input, size_t length, - char16_t *utf16_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf32_to_utf16be(const char32_t* input, size_t length, + char16_t* utf16Buffer) const noexcept -> size_t = 0; - /** + /** * Convert possibly broken UTF-32 string into UTF-16LE string and stop on * error. * @@ -13072,11 +12209,11 @@ class implementation { * (in the input in code units) if any, or the number of char16_t written if * successful. */ - simdutf_warn_unused virtual result convert_utf32_to_utf16le_with_errors( - const char32_t *input, size_t length, - char16_t *utf16_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf32_to_utf16le_with_errors(const char32_t* input, size_t length, + char16_t* utf16Buffer) const noexcept + -> result = 0; - /** + /** * Convert possibly broken UTF-32 string into UTF-16BE string and stop on * error. * @@ -13094,11 +12231,11 @@ class implementation { * (in the input in code units) if any, or the number of char16_t written if * successful. */ - simdutf_warn_unused virtual result convert_utf32_to_utf16be_with_errors( - const char32_t *input, size_t length, - char16_t *utf16_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_utf32_to_utf16be_with_errors(const char32_t* input, size_t length, + char16_t* utf16Buffer) const noexcept + -> result = 0; - /** + /** * Convert valid UTF-32 string into UTF-16LE string. * * This function assumes that the input string is valid UTF-32. @@ -13112,11 +12249,10 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf32_to_utf16le(const char32_t *input, size_t length, - char16_t *utf16_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf32_to_utf16le(const char32_t* input, size_t length, + char16_t* utf16Buffer) const noexcept -> size_t = 0; - /** + /** * Convert valid UTF-32 string into UTF-16BE string. * * This function assumes that the input string is valid UTF-32. @@ -13130,9 +12266,8 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual size_t - convert_valid_utf32_to_utf16be(const char32_t *input, size_t length, - char16_t *utf16_buffer) const noexcept = 0; + simdutf_warn_unused virtual auto convert_valid_utf32_to_utf16be(const char32_t* input, size_t length, + char16_t* utf16Buffer) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 @@ -13163,8 +12298,8 @@ class implementation { * @param length the length of the string bytes * @return the number of bytes required to encode the Latin1 string as UTF-8 */ - simdutf_warn_unused virtual size_t - utf8_length_from_latin1(const char *input, size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf8_length_from_latin1(const char* input, size_t length) const noexcept + -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -13180,9 +12315,8 @@ class implementation { * (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-8 */ - simdutf_warn_unused virtual size_t - utf8_length_from_utf32(const char32_t *input, - size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf8_length_from_utf32(const char32_t* input, size_t length) const noexcept + -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -13197,9 +12331,8 @@ class implementation { * (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ - simdutf_warn_unused virtual size_t - latin1_length_from_utf32(size_t length) const noexcept { - return length; + simdutf_warn_unused virtual auto latin1_length_from_utf32(size_t length) const noexcept -> size_t { + return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -13215,8 +12348,8 @@ class implementation { * @param length the length of the string in byte * @return the number of bytes required to encode the UTF-8 string as Latin1 */ - simdutf_warn_unused virtual size_t - latin1_length_from_utf8(const char *input, size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto latin1_length_from_utf8(const char* input, size_t length) const noexcept + -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -13235,9 +12368,8 @@ class implementation { * @return the number of bytes required to encode the UTF-16LE string as * Latin1 */ - simdutf_warn_unused virtual size_t - latin1_length_from_utf16(size_t length) const noexcept { - return length; + simdutf_warn_unused virtual auto latin1_length_from_utf16(size_t length) const noexcept -> size_t { + return length; } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -13254,9 +12386,8 @@ class implementation { * (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-16 */ - simdutf_warn_unused virtual size_t - utf16_length_from_utf32(const char32_t *input, - size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf16_length_from_utf32(const char32_t* input, size_t length) const noexcept + -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -13268,9 +12399,8 @@ class implementation { * (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ - simdutf_warn_unused virtual size_t - utf32_length_from_latin1(size_t length) const noexcept { - return length; + simdutf_warn_unused virtual auto utf32_length_from_latin1(size_t length) const noexcept -> size_t { + return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -13292,9 +12422,8 @@ class implementation { * @return the number of bytes required to encode the UTF-16LE string as * UTF-32 */ - simdutf_warn_unused virtual size_t - utf32_length_from_utf16le(const char16_t *input, - size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf32_length_from_utf16le(const char16_t* input, size_t length) const noexcept + -> size_t = 0; /** * Compute the number of bytes that this UTF-16BE string would require in @@ -13313,9 +12442,8 @@ class implementation { * @return the number of bytes required to encode the UTF-16BE string as * UTF-32 */ - simdutf_warn_unused virtual size_t - utf32_length_from_utf16be(const char16_t *input, - size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto utf32_length_from_utf16be(const char16_t* input, size_t length) const noexcept + -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 @@ -13334,8 +12462,7 @@ class implementation { * (char16_t) * @return number of code points */ - simdutf_warn_unused virtual size_t - count_utf16le(const char16_t *input, size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto count_utf16le(const char16_t* input, size_t length) const noexcept -> size_t = 0; /** * Count the number of code points (characters) in the string assuming that @@ -13352,8 +12479,7 @@ class implementation { * (char16_t) * @return number of code points */ - simdutf_warn_unused virtual size_t - count_utf16be(const char16_t *input, size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto count_utf16be(const char16_t* input, size_t length) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 @@ -13369,8 +12495,7 @@ class implementation { * @param length the length of the string in bytes * @return number of code points */ - simdutf_warn_unused virtual size_t - count_utf8(const char *input, size_t length) const noexcept = 0; + simdutf_warn_unused virtual auto count_utf8(const char* input, size_t length) const noexcept -> size_t = 0; #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_BASE64 @@ -13387,8 +12512,7 @@ class implementation { * @param length the length of the base64 input in bytes * @return maximal number of binary bytes */ - simdutf_warn_unused size_t maximal_binary_length_from_base64( - const char *input, size_t length) const noexcept; + simdutf_warn_unused auto maximal_binary_length_from_base64(const char* input, size_t length) const noexcept -> size_t; /** * Provide the maximal binary length in bytes given the base64 input. @@ -13404,8 +12528,8 @@ class implementation { * @param length the length of the base64 input in 16-bit units * @return maximal number of binary bytes */ - simdutf_warn_unused size_t maximal_binary_length_from_base64( - const char16_t *input, size_t length) const noexcept; + simdutf_warn_unused auto maximal_binary_length_from_base64(const char16_t* input, size_t length) const noexcept + -> size_t; /** * Compute the binary length from a base64 input with ASCII spaces. @@ -13419,8 +12543,7 @@ class implementation { * @param length the length of the base64 input in bytes * @return number of binary bytes */ - simdutf_warn_unused virtual size_t - binary_length_from_base64(const char *input, size_t length) const noexcept; + simdutf_warn_unused virtual auto binary_length_from_base64(const char* input, size_t length) const noexcept -> size_t; /** * Compute the binary length from a base64 input with ASCII spaces. @@ -13435,9 +12558,8 @@ class implementation { * @param length the length of the base64 input in 16-bit units * @return number of binary bytes */ - simdutf_warn_unused virtual size_t - binary_length_from_base64(const char16_t *input, - size_t length) const noexcept; + simdutf_warn_unused virtual auto binary_length_from_base64(const char16_t* input, size_t length) const noexcept + -> size_t; /** * Convert a base64 input to a binary output. @@ -13471,11 +12593,9 @@ class implementation { * (in the input in bytes) if any, or the number of bytes written if * successful. */ - simdutf_warn_unused virtual result - base64_to_binary(const char *input, size_t length, char *output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose) const noexcept = 0; + simdutf_warn_unused virtual auto base64_to_binary( + const char* input, size_t length, char* output, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) const noexcept -> result = 0; /** * Convert a base64 input to a binary output while returning more details @@ -13508,11 +12628,10 @@ class implementation { * @return a full_result pair struct (of type simdutf::result containing the * three fields error, input_count and output_count). */ - simdutf_warn_unused virtual full_result base64_to_binary_details( - const char *input, size_t length, char *output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose) const noexcept = 0; + simdutf_warn_unused virtual auto base64_to_binary_details( + const char* input, size_t length, char* output, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) const noexcept + -> full_result = 0; /** * Convert a base64 input to a binary output. @@ -13547,11 +12666,9 @@ class implementation { * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the * number of bytes written if successful. */ - simdutf_warn_unused virtual result - base64_to_binary(const char16_t *input, size_t length, char *output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose) const noexcept = 0; + simdutf_warn_unused virtual auto base64_to_binary( + const char16_t* input, size_t length, char* output, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) const noexcept -> result = 0; /** * Convert a base64 input to a binary output while returning more details @@ -13584,11 +12701,10 @@ class implementation { * @return a full_result pair struct (of type simdutf::result containing the * three fields error, input_count and output_count). */ - simdutf_warn_unused virtual full_result base64_to_binary_details( - const char16_t *input, size_t length, char *output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = - last_chunk_handling_options::loose) const noexcept = 0; + simdutf_warn_unused virtual auto base64_to_binary_details( + const char16_t* input, size_t length, char* output, base64_options options = base64_default, + last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) const noexcept + -> full_result = 0; /** * Provide the base64 length in bytes given the length of a binary input. @@ -13598,8 +12714,8 @@ class implementation { * base64_url, is base64_default by default. * @return number of base64 bytes */ - simdutf_warn_unused size_t base64_length_from_binary( - size_t length, base64_options options = base64_default) const noexcept; + simdutf_warn_unused auto base64_length_from_binary(size_t length, + base64_options options = base64_default) const noexcept -> size_t; /** * Convert a binary input to a base64 output. @@ -13622,9 +12738,8 @@ class implementation { * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ - virtual size_t - binary_to_base64(const char *input, size_t length, char *output, - base64_options options = base64_default) const noexcept = 0; + virtual auto binary_to_base64(const char* input, size_t length, char* output, + base64_options options = base64_default) const noexcept -> size_t = 0; /** * Convert a binary input to a base64 output with lines of given length. @@ -13651,10 +12766,9 @@ class implementation { * @return number of written bytes, will be equal to * base64_length_from_binary_with_lines(length, options, line_length) */ - virtual size_t binary_to_base64_with_lines( - const char *input, size_t length, char *output, - size_t line_length = simdutf::default_line_length, - base64_options options = base64_default) const noexcept = 0; + virtual auto binary_to_base64_with_lines(const char* input, size_t length, char* output, + size_t lineLength = simdutf::defaultLineLength, + base64_options options = base64_default) const noexcept -> size_t = 0; /** * Find the first occurrence of a character in a string. If the character is @@ -13666,10 +12780,9 @@ class implementation { * or a pointer to the end of the string if the character is not found. * */ - virtual const char *find(const char *start, const char *end, - char character) const noexcept = 0; - virtual const char16_t *find(const char16_t *start, const char16_t *end, - char16_t character) const noexcept = 0; + virtual auto find(const char* start, const char* end, char character) const noexcept -> const char* = 0; + virtual auto find(const char16_t* start, const char16_t* end, char16_t character) const noexcept -> const + char16_t* = 0; #endif // SIMDUTF_FEATURE_BASE64 #ifdef SIMDUTF_INTERNAL_TESTS @@ -13695,14 +12808,12 @@ class implementation { protected: /** @private Construct an implementation with the given name and description. * For subclasses. */ - simdutf_really_inline implementation(const char *name, - const char *description, - uint32_t required_instruction_sets) - : _name(name), _description(description), - _required_instruction_sets(required_instruction_sets) {} + simdutf_really_inline implementation(const char* name, const char* description, uint32_t requiredInstructionSets) + : _name(name) + , _description(description) + , _requiredInstructionSets(requiredInstructionSets) {} -protected: - ~implementation() = default; + ~implementation() = default; private: /** @@ -13718,7 +12829,7 @@ class implementation { /** * Instruction sets required for this implementation. */ - const uint32_t _required_instruction_sets; + const uint32_t _requiredInstructionSets; }; /** @private */ @@ -13730,15 +12841,15 @@ namespace internal { class available_implementation_list { public: /** Get the list of available implementations compiled into simdutf */ - simdutf_really_inline available_implementation_list() {} - /** Number of implementations */ - size_t size() const noexcept; - /** STL const begin() iterator */ - const implementation *const *begin() const noexcept; - /** STL const end() iterator */ - const implementation *const *end() const noexcept; - - /** + simdutf_really_inline available_implementation_list() = default; + /** Number of implementations */ + [[nodiscard]] auto size() const noexcept -> size_t; + /** STL const begin() iterator */ + [[nodiscard]] auto begin() const noexcept -> const implementation* const*; + /** STL const end() iterator */ + [[nodiscard]] auto end() const noexcept -> const implementation* const*; + + /** * Get the implementation with the given name. * * Case sensitive. @@ -13751,14 +12862,14 @@ class available_implementation_list { * @param name the implementation to find, e.g. "westmere", "haswell", "arm64" * @return the implementation, or nullptr if the parse failed. */ - const implementation *operator[](std::string_view name) const noexcept { - for (const implementation *impl : *this) { - if (impl->name() == name) { - return impl; - } + auto operator[](std::string_view name) const noexcept -> const implementation* { + for (const implementation* impl : *this) { + if (impl->name() == name) { + return impl; + } + } + return nullptr; } - return nullptr; - } /** * Detect the most advanced implementation supported by the current host. @@ -13773,46 +12884,71 @@ class available_implementation_list { * an implementation that returns UNSUPPORTED_ARCHITECTURE if there is no * supported implementation. Will never return nullptr. */ - const implementation *detect_best_supported() const noexcept; + [[nodiscard]] auto detect_best_supported() const noexcept -> const implementation*; }; template class atomic_ptr { public: - atomic_ptr(T *_ptr) : ptr{_ptr} {} + atomic_ptr(T* ptr) + : _ptr{ptr} {} -#if defined(SIMDUTF_NO_THREADS) - operator const T *() const { return ptr; } - const T &operator*() const { return *ptr; } - const T *operator->() const { return ptr; } +#ifdef SIMDUTF_NO_THREADS + operator const T*() const { + return ptr; + } + const T& operator*() const { + return *ptr; + } + const T* operator->() const { + return ptr; + } - operator T *() { return ptr; } - T &operator*() { return *ptr; } - T *operator->() { return ptr; } - atomic_ptr &operator=(T *_ptr) { - ptr = _ptr; - return *this; - } + operator T*() { + return ptr; + } + T& operator*() { + return *ptr; + } + T* operator->() { + return ptr; + } + atomic_ptr& operator=(T* _ptr) { + ptr = _ptr; + return *this; + } #else - operator const T *() const { return ptr.load(); } - const T &operator*() const { return *ptr; } - const T *operator->() const { return ptr.load(); } + operator const T *() const { + return _ptr.load(); + } + auto operator*() const -> const T& { + return *_ptr; + } + auto operator->() const -> const T* { + return _ptr.load(); + } - operator T *() { return ptr.load(); } - T &operator*() { return *ptr; } - T *operator->() { return ptr.load(); } - atomic_ptr &operator=(T *_ptr) { - ptr = _ptr; - return *this; + operator T *() { + return _ptr.load(); + } + auto operator*() -> T& { + return *_ptr; + } + auto operator->() -> T* { + return _ptr.load(); + } + auto operator=(T* ptr) -> atomic_ptr& { + _ptr = ptr; + return *this; } #endif private: -#if defined(SIMDUTF_NO_THREADS) - T *ptr; +#ifdef SIMDUTF_NO_THREADS + T* ptr; #else - std::atomic ptr; + std::atomic _ptr; #endif }; @@ -13823,8 +12959,7 @@ class detect_best_supported_implementation_on_first_use; /** * The list of available implementations compiled into simdutf. */ -extern SIMDUTF_DLLIMPORTEXPORT const internal::available_implementation_list & -get_available_implementations(); +extern SIMDUTF_DLLIMPORTEXPORT auto get_available_implementations() -> const internal::available_implementation_list&; /** * The active implementation. @@ -13832,8 +12967,7 @@ get_available_implementations(); * Automatically initialized on first use to the most advanced implementation * supported by this hardware. */ -extern SIMDUTF_DLLIMPORTEXPORT internal::atomic_ptr & -get_active_implementation(); +extern SIMDUTF_DLLIMPORTEXPORT auto get_active_implementation() -> internal::atomic_ptr&; } // namespace simdutf @@ -13848,152 +12982,136 @@ get_active_implementation(); namespace simdutf { template -simdutf_warn_unused simdutf_constexpr23 result slow_base64_to_binary_safe_impl( - const chartype *input, size_t length, char *output, size_t &outlen, - base64_options options, - last_chunk_handling_options last_chunk_options) noexcept { - const bool ignore_garbage = (options & base64_default_accept_garbage) != 0; - auto ri = simdutf::scalar::base64::find_end(input, length, options); - size_t equallocation = ri.equallocation; - size_t equalsigns = ri.equalsigns; - length = ri.srclen; - size_t full_input_length = ri.full_input_length; - (void)full_input_length; - if (length == 0) { - outlen = 0; - if (!ignore_garbage && equalsigns > 0) { - return {INVALID_BASE64_CHARACTER, equallocation}; - } - return {SUCCESS, 0}; - } - - // The parameters of base64_tail_decode_safe are: - // - dst: the output buffer - // - outlen: the size of the output buffer - // - srcr: the input buffer - // - length: the size of the input buffer - // - padded_characters: the number of padding characters - // - options: the options for the base64 decoder - // - last_chunk_options: the options for the last chunk - // The function will return the number of bytes written to the output buffer - // and the number of bytes read from the input buffer. - // The function will also return an error code if the input buffer is not - // valid base64. - full_result r = scalar::base64::base64_tail_decode_safe( - output, outlen, input, length, equalsigns, options, last_chunk_options); - r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, - full_input_length, last_chunk_options); - outlen = r.output_count; - if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && - equalsigns > 0) { - // additional checks - if ((outlen % 3 == 0) || ((outlen % 3) + 1 + equalsigns != 4)) { - r.error = error_code::INVALID_BASE64_CHARACTER; - } - } - return {r.error, r.input_count}; // we cannot return r itself because it gets - // converted to error/output_count +simdutf_warn_unused simdutf_constexpr23 auto slow_base64_to_binary_safe_impl( + const chartype* input, size_t length, char* output, size_t& outlen, base64_options options, + last_chunk_handling_options lastChunkOptions) noexcept -> result { + const bool ignoreGarbage = (options & base64_default_accept_garbage) != 0; + auto ri = simdutf::scalar::base64::find_end(input, length, options); + size_t equallocation = ri.equallocation; + size_t equalsigns = ri.equalsigns; + length = ri.srclen; + size_t fullInputLength = ri.full_input_length; + (void)fullInputLength; + if (length == 0) { + outlen = 0; + if (!ignoreGarbage && equalsigns > 0) { + return {INVALID_BASE64_CHARACTER, equallocation}; + } + return {SUCCESS, 0}; + } + + // The parameters of base64_tail_decode_safe are: + // - dst: the output buffer + // - outlen: the size of the output buffer + // - srcr: the input buffer + // - length: the size of the input buffer + // - padded_characters: the number of padding characters + // - options: the options for the base64 decoder + // - last_chunk_options: the options for the last chunk + // The function will return the number of bytes written to the output buffer + // and the number of bytes read from the input buffer. + // The function will also return an error code if the input buffer is not + // valid base64. + full_result r = + scalar::base64::base64_tail_decode_safe(output, outlen, input, length, equalsigns, options, lastChunkOptions); + r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, fullInputLength, lastChunkOptions); + outlen = r.outputCount; + if (!is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && equalsigns > 0) { + // additional checks + if ((outlen % 3 == 0) || ((outlen % 3) + 1 + equalsigns != 4)) { + r.error = error_code::INVALID_BASE64_CHARACTER; + } + } + return {r.error, r.input_count}; // we cannot return r itself because it gets + // converted to error/output_count } template -simdutf_warn_unused simdutf_constexpr23 result base64_to_binary_safe_impl( - const chartype *input, size_t length, char *output, size_t &outlen, - base64_options options, - last_chunk_handling_options last_chunk_handling_options, - bool decode_up_to_bad_char) noexcept { - static_assert(std::is_same::value || - std::is_same::value, - "Only char and char16_t are supported."); - size_t remaining_input_length = length; - size_t remaining_output_length = outlen; - size_t input_position = 0; - size_t output_position = 0; - - // We also do a first pass using the fast path to decode as much as possible - size_t safe_input = (std::min)( - remaining_input_length, - base64_length_from_binary(remaining_output_length / 3 * 3, options)); - bool done_with_partial = (safe_input == remaining_input_length); - simdutf::full_result r; +simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_safe_impl( + const chartype* input, size_t length, char* output, size_t& outlen, base64_options options, + last_chunk_handling_options lastChunkHandlingOptions, bool decodeUpToBadChar) noexcept -> result { + static_assert(std::is_same_v || std::is_same_v, + "Only char and char16_t are supported."); + size_t remainingInputLength = length; + size_t remainingOutputLength = outlen; + size_t inputPosition = 0; + size_t outputPosition = 0; + + // We also do a first pass using the fast path to decode as much as possible + size_t safeInput = + (std::min)(remainingInputLength, base64_length_from_binary(remainingOutputLength / 3 * 3, options)); + bool doneWithPartial = (safeInput == remainingInputLength); + simdutf::full_result r; #if SIMDUTF_CPLUSPLUS23 if consteval { - r = scalar::base64::base64_to_binary_details_impl( - input + input_position, safe_input, output + output_position, options, - done_with_partial - ? last_chunk_handling_options - : simdutf::last_chunk_handling_options::only_full_chunks); + r = scalar::base64::base64_to_binary_details_impl( + input + inputPosition, safeInput, output + outputPosition, options, + doneWithPartial ? lastChunkHandlingOptions : simdutf::last_chunk_handling_options::only_full_chunks); } else #endif { - r = get_active_implementation()->base64_to_binary_details( - input + input_position, safe_input, output + output_position, options, - done_with_partial - ? last_chunk_handling_options - : simdutf::last_chunk_handling_options::only_full_chunks); + r = get_active_implementation()->base64_to_binary_details( + input + inputPosition, safeInput, output + outputPosition, options, + doneWithPartial ? lastChunkHandlingOptions : simdutf::last_chunk_handling_options::only_full_chunks); } simdutf_log_assert(r.input_count <= safe_input, "You should not read more than safe_input"); simdutf_log_assert(r.output_count <= remaining_output_length, "You should not write more than remaining_output_length"); // Technically redundant, but we want to be explicit about it. - input_position += r.input_count; - output_position += r.output_count; - remaining_input_length -= r.input_count; - remaining_output_length -= r.output_count; + inputPosition += r.input_count; + outputPosition += r.outputCount; + remainingInputLength -= r.input_count; + remainingOutputLength -= r.outputCount; if (r.error != simdutf::error_code::SUCCESS) { // There is an error. We return. - if (decode_up_to_bad_char && - r.error == error_code::INVALID_BASE64_CHARACTER) { - return slow_base64_to_binary_safe_impl( - input, length, output, outlen, options, last_chunk_handling_options); + if (decodeUpToBadChar && r.error == error_code::INVALID_BASE64_CHARACTER) { + return slow_base64_to_binary_safe_impl(input, length, output, outlen, options, lastChunkHandlingOptions); } - outlen = output_position; - return {r.error, input_position}; + outlen = outputPosition; + return {r.error, inputPosition}; } - if (done_with_partial) { - // We are done. We have decoded everything. - outlen = output_position; - return {simdutf::error_code::SUCCESS, input_position}; + if (doneWithPartial) { + // We are done. We have decoded everything. + outlen = outputPosition; + return {simdutf::error_code::SUCCESS, inputPosition}; } // We have decoded some data, but we still have some data to decode. // We need to decode the rest of the input buffer. - r = simdutf::scalar::base64::base64_to_binary_details_safe_impl( - input + input_position, remaining_input_length, output + output_position, - remaining_output_length, options, last_chunk_handling_options); - input_position += r.input_count; - output_position += r.output_count; - remaining_input_length -= r.input_count; - remaining_output_length -= r.output_count; + r = simdutf::scalar::base64::base64_to_binary_details_safe_impl(input + inputPosition, remainingInputLength, + output + outputPosition, remainingOutputLength, + options, lastChunkHandlingOptions); + inputPosition += r.input_count; + outputPosition += r.outputCount; + remainingInputLength -= r.input_count; + remainingOutputLength -= r.outputCount; if (r.error != simdutf::error_code::SUCCESS) { // There is an error. We return. - if (decode_up_to_bad_char && - r.error == error_code::INVALID_BASE64_CHARACTER) { - return slow_base64_to_binary_safe_impl( - input, length, output, outlen, options, last_chunk_handling_options); + if (decodeUpToBadChar && r.error == error_code::INVALID_BASE64_CHARACTER) { + return slow_base64_to_binary_safe_impl(input, length, output, outlen, options, lastChunkHandlingOptions); } - outlen = output_position; - return {r.error, input_position}; + outlen = outputPosition; + return {r.error, inputPosition}; } - if (input_position < length) { - // We cannot process the entire input in one go, so we need to - // process it in two steps: first the fast path, then the slow path. - // In some cases, the processing might 'eat up' trailing ignorable - // characters in the fast path, but that can be a problem. - // suppose we have just white space followed by a single base64 character. - // If we first process the white space with the fast path, it will - // eat all of it. But, by the JavaScript standard, we should consume - // no character. See - // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 - while (input_position > 0 && - base64_ignorable(input[input_position - 1], options)) { - input_position--; - } + if (inputPosition < length) { + // We cannot process the entire input in one go, so we need to + // process it in two steps: first the fast path, then the slow path. + // In some cases, the processing might 'eat up' trailing ignorable + // characters in the fast path, but that can be a problem. + // suppose we have just white space followed by a single base64 character. + // If we first process the white space with the fast path, it will + // eat all of it. But, by the JavaScript standard, we should consume + // no character. See + // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 + while (inputPosition > 0 && base64_ignorable(input[inputPosition - 1], options)) { + inputPosition--; + } } - outlen = output_position; - return {simdutf::error_code::SUCCESS, input_position}; + outlen = outputPosition; + return {simdutf::error_code::SUCCESS, inputPosition}; } } // namespace simdutf @@ -14006,71 +13124,58 @@ namespace simdutf { * @brief span overload * @return a tuple of result and outlen */ -simdutf_really_inline - simdutf_constexpr23 simdutf_warn_unused std::tuple - base64_to_binary_safe( - const detail::input_span_of_byte_like auto &input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose, - bool decode_up_to_bad_char = false) noexcept { - size_t outlen = binary_output.size(); - #if SIMDUTF_CPLUSPLUS23 - if consteval { - using CInput = std::decay_t; - static_assert(std::is_same_v, - "sorry, the constexpr implementation is for now limited to " - "input of type char"); - using COutput = std::decay_t; - static_assert(std::is_same_v, - "sorry, the constexpr implementation is for now limited to " - "output of type char"); - auto r = base64_to_binary_safe_impl( - input.data(), input.size(), binary_output.data(), outlen, options, - last_chunk_options, decode_up_to_bad_char); - return {r, outlen}; - } else - #endif - { - auto r = base64_to_binary_safe_impl( - reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binary_output.data()), outlen, options, - last_chunk_options, decode_up_to_bad_char); - return {r, outlen}; +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto base64_to_binary_safe( + const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose, + bool decodeUpToBadChar = false) noexcept -> std::tuple { + size_t outlen = binaryOutput.size(); +#if SIMDUTF_CPLUSPLUS23 + if consteval { + using CInput = std::decay_t; + static_assert(std::is_same_v, + "sorry, the constexpr implementation is for now limited to " + "input of type char"); + using COutput = std::decay_t; + static_assert(std::is_same_v, + "sorry, the constexpr implementation is for now limited to " + "output of type char"); + auto r = base64_to_binary_safe_impl(input.data(), input.size(), binaryOutput.data(), outlen, options, + lastChunkOptions, decodeUpToBadChar); + return {r, outlen}; + } else +#endif + { + auto r = base64_to_binary_safe_impl(reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binaryOutput.data()), outlen, options, + lastChunkOptions, decodeUpToBadChar); + return {r, outlen}; } } - #if SIMDUTF_SPAN +#if SIMDUTF_SPAN /** * @brief span overload * @return a tuple of result and outlen */ -simdutf_really_inline - simdutf_warn_unused simdutf_constexpr23 std::tuple - base64_to_binary_safe( - std::span input, - detail::output_span_of_byte_like auto &&binary_output, - base64_options options = base64_default, - last_chunk_handling_options last_chunk_options = loose, - bool decode_up_to_bad_char = false) noexcept { - size_t outlen = binary_output.size(); - #if SIMDUTF_CPLUSPLUS23 - if consteval { - auto r = base64_to_binary_safe_impl( - input.data(), input.size(), binary_output.data(), outlen, options, - last_chunk_options, decode_up_to_bad_char); - return {r, outlen}; - } else - #endif - { - auto r = base64_to_binary_safe( - input.data(), input.size(), - reinterpret_cast(binary_output.data()), outlen, options, - last_chunk_options, decode_up_to_bad_char); - return {r, outlen}; +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_safe( + std::span input, detail::output_span_of_byte_like auto&& binaryOutput, + base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose, + bool decodeUpToBadChar = false) noexcept -> std::tuple { + size_t outlen = binaryOutput.size(); +#if SIMDUTF_CPLUSPLUS23 + if consteval { + auto r = base64_to_binary_safe_impl(input.data(), input.size(), binaryOutput.data(), outlen, options, + lastChunkOptions, decodeUpToBadChar); + return {r, outlen}; + } else +#endif + { + auto r = base64_to_binary_safe(input.data(), input.size(), reinterpret_cast(binaryOutput.data()), outlen, + options, lastChunkOptions, decodeUpToBadChar); + return {r, outlen}; } } - #endif // SIMDUTF_SPAN +#endif // SIMDUTF_SPAN #endif // SIMDUTF_SPAN } // namespace simdutf @@ -14079,8 +13184,7 @@ simdutf_really_inline #if SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64 -namespace simdutf { -namespace literals { +namespace simdutf::literals { namespace detail { @@ -14088,7 +13192,9 @@ namespace detail { template struct base64_literal_helper { std::array storage{}; - static constexpr std::size_t size() noexcept { return N - 1; } + static constexpr auto size() noexcept -> std::size_t { + return N - 1; + } consteval base64_literal_helper(const char (&str)[N]) { for (std::size_t i = 0; i < size(); i++) { storage[i] = str[i]; @@ -14097,9 +13203,9 @@ template struct base64_literal_helper { }; template struct base64_decode_result { - static constexpr std::size_t max_out = (InputLen + 3) / 4 * 3; - std::array buffer{}; - std::size_t output_count{}; + static constexpr std::size_t maxOut = (InputLen + 3) / 4 * 3; + std::array buffer{}; + std::size_t outputCount{}; }; template @@ -14140,8 +13246,7 @@ template consteval auto operator""_base64() { return detail::base64_make_array(); } -} // namespace literals -} // namespace simdutf +} // namespace simdutf::literals #endif // SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64 diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h index 6cfe33018..018f115ba 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h @@ -4,32 +4,28 @@ #include namespace Embedded { - inline const std::wstring& InfiniFrameJsUtf16() { - static const std::wstring cached = [] { - const auto* src = reinterpret_cast(g_infiniframe_js_data); - - std::u16string temp; - temp.resize(simdutf::utf16_length_from_utf8(src, g_infiniframe_js_size)); - - const size_t written = simdutf::convert_utf8_to_utf16( - src, - g_infiniframe_js_size, - temp.data() - ); - - temp.resize(written); - - return std::wstring(temp.begin(), temp.end()); - }(); - - return cached; - } - - inline const std::string& InfiniFrameJsUtf8() { - static const std::string cached = [] { - const auto* src = reinterpret_cast(g_infiniframe_js_data); - return std::string(src, g_infiniframe_js_size); - }(); - return cached; - } +inline const std::wstring& InfiniFrameJsUtf16() { + static const std::wstring cached = [] { + const auto* src = reinterpret_cast(g_infiniframe_js_data); + + std::u16string temp; + temp.resize(simdutf::utf16_length_from_utf8(src, g_infiniframe_js_size)); + + const size_t written = simdutf::convert_utf8_to_utf16(src, g_infiniframe_js_size, temp.data()); + + temp.resize(written); + + return std::wstring(temp.begin(), temp.end()); + }(); + + return cached; +} + +inline const std::string& InfiniFrameJsUtf8() { + static const std::string cached = [] { + const auto* src = reinterpret_cast(g_infiniframe_js_data); + return std::string(src, g_infiniframe_js_size); + }(); + return cached; } +} // namespace Embedded diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp index 3b33bd38a..191a3066c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp @@ -6,25 +6,25 @@ #include "../Window.Gtk.Internal.h" namespace { - std::mutex invokeLockMutex; - - struct InvokeWaitInfo { - ACTION callback; - std::condition_variable completionNotifier; - bool isCompleted; - }; - - gboolean invokeCallback(const gpointer data) { - auto* waitInfo = reinterpret_cast(data); - waitInfo->callback(); - { - std::lock_guard guard(invokeLockMutex); - waitInfo->isCompleted = true; - } - waitInfo->completionNotifier.notify_one(); - return false; +std::mutex invokeLockMutex; + +struct InvokeWaitInfo { + ACTION callback; + std::condition_variable completionNotifier; + bool isCompleted; +}; + +gboolean invokeCallback(const gpointer data) { + auto* waitInfo = reinterpret_cast(data); + waitInfo->callback(); + { + std::lock_guard guard(invokeLockMutex); + waitInfo->isCompleted = true; } + waitInfo->completionNotifier.notify_one(); + return false; } +} // namespace void InfiniFrameWindow::Invoke(const ACTION callback) { InvokeWaitInfo waitInfo = {}; @@ -32,11 +32,7 @@ void InfiniFrameWindow::Invoke(const ACTION callback) { gdk_threads_add_idle(invokeCallback, &waitInfo); std::unique_lock uLock(invokeLockMutex); - waitInfo.completionNotifier.wait( - uLock, [&] { - return waitInfo.isCompleted; - } - ); + waitInfo.completionNotifier.wait(uLock, [&] { return waitInfo.isCompleted; }); } #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp index d484036a0..f576681ea 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp @@ -5,8 +5,8 @@ #include "../Window.Gtk.Internal.h" -InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) : - m_impl(std::make_unique()) { +InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) + : m_impl(std::make_unique()) { XInitThreads(); gtk_init(nullptr, nullptr); notify_init(initParams->Title); @@ -14,9 +14,9 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) : if (initParams->Size != sizeof(InfiniFrameInitParams)) { GtkWidget* dialog = gtk_message_dialog_new( nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "Initial parameters passed are %i bytes, but expected %lu bytes.", - initParams->Size, sizeof(InfiniFrameInitParams) - ); + "Initial parameters passed are %i bytes, but expected %lu bytes.", initParams->Size, + sizeof(InfiniFrameInitParams) + ); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); exit(0); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp index 9e1bb3288..677676b85 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp @@ -17,7 +17,7 @@ gboolean on_webview_context_menu( WebKitHitTestResult* hit_test_result, gboolean triggered_with_keyboard, gpointer user_data - ); +); gboolean on_permission_request(WebKitWebView* web_view, WebKitPermissionRequest* request, gpointer user_data); void InfiniFrameWindow::Impl::InitializeFromParams(const InfiniFrameInitParams* initParams) { @@ -110,9 +110,8 @@ void InfiniFrameWindow::Impl::ConfigureInitialWindow(InfiniFrameWindow* window, } void InfiniFrameWindow::Impl::ApplyInitialWindowState( - InfiniFrameWindow* window, - const InfiniFrameInitParams* initParams - ) { + InfiniFrameWindow* window, const InfiniFrameInitParams* initParams +) { window->SetTitle(const_cast(_windowTitle.c_str())); if (initParams->Chromeless) @@ -134,47 +133,23 @@ void InfiniFrameWindow::Impl::ApplyInitialWindowState( } void InfiniFrameWindow::Impl::ConnectWindowSignals(InfiniFrameWindow* window) { - g_signal_connect( - G_OBJECT(_window), "configure-event", - G_CALLBACK(on_configure_event), window - ); - - g_signal_connect( - G_OBJECT(_window), "window-state-event", - G_CALLBACK(on_window_state_event), window - ); - - g_signal_connect( - G_OBJECT(_window), "delete-event", - G_CALLBACK(on_widget_deleted), window - ); - - g_signal_connect( - G_OBJECT(_window), "destroy", - G_CALLBACK(on_widget_destroyed), window - ); - - g_signal_connect( - G_OBJECT(_window), "focus-in-event", - G_CALLBACK(on_focus_in_event), window - ); - - g_signal_connect( - G_OBJECT(_window), "focus-out-event", - G_CALLBACK(on_focus_out_event), window - ); + g_signal_connect(G_OBJECT(_window), "configure-event", G_CALLBACK(on_configure_event), window); + + g_signal_connect(G_OBJECT(_window), "window-state-event", G_CALLBACK(on_window_state_event), window); + + g_signal_connect(G_OBJECT(_window), "delete-event", G_CALLBACK(on_widget_deleted), window); + + g_signal_connect(G_OBJECT(_window), "destroy", G_CALLBACK(on_widget_destroyed), window); + + g_signal_connect(G_OBJECT(_window), "focus-in-event", G_CALLBACK(on_focus_in_event), window); + + g_signal_connect(G_OBJECT(_window), "focus-out-event", G_CALLBACK(on_focus_out_event), window); } void InfiniFrameWindow::Impl::ConnectWebViewSignals(InfiniFrameWindow* window) { - g_signal_connect( - G_OBJECT(_webview), "context-menu", - G_CALLBACK(on_webview_context_menu), window - ); - - g_signal_connect( - G_OBJECT(_webview), "permission-request", - G_CALLBACK(on_permission_request), window - ); + g_signal_connect(G_OBJECT(_webview), "context-menu", G_CALLBACK(on_webview_context_menu), window); + + g_signal_connect(G_OBJECT(_webview), "permission-request", G_CALLBACK(on_permission_request), window); } #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp index 7b500b14e..6c1b03c5a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp @@ -37,11 +37,7 @@ void InfiniFrameWindow::Center() { gdk_monitor_get_geometry(m, &screen); - gtk_window_move( - GTK_WINDOW(m_impl->_window), - (screen.width - windowWidth) / 2, - (screen.height - windowHeight) / 2 - ); + gtk_window_move(GTK_WINDOW(m_impl->_window), (screen.width - windowWidth) / 2, (screen.height - windowHeight) / 2); } void InfiniFrameWindow::ClearBrowserAutoFill() { @@ -61,13 +57,7 @@ void InfiniFrameWindow::ShowNotification(const AutoString title, const AutoStrin void InfiniFrameWindow::WaitForExit() { g_signal_connect( - G_OBJECT(m_impl->_window), "destroy", - G_CALLBACK( - +[](GtkWidget*, gpointer) { - gtk_main_quit(); - } - ), - nullptr + G_OBJECT(m_impl->_window), "destroy", G_CALLBACK(+[](GtkWidget*, gpointer) { gtk_main_quit(); }), nullptr ); gtk_main(); } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp index 222f62609..262d09c5c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp @@ -5,39 +5,39 @@ #include "../Window.Gtk.Internal.h" namespace { - bool linux_webview_diagnostics_enabled() { - const char* value = g_getenv("INFINIFRAME_LINUX_WEBVIEW_DIAGNOSTICS"); - return value != nullptr && value[0] != '\0' && g_strcmp0(value, "0") != 0; - } +bool linux_webview_diagnostics_enabled() { + const char* value = g_getenv("INFINIFRAME_LINUX_WEBVIEW_DIAGNOSTICS"); + return value != nullptr && value[0] != '\0' && g_strcmp0(value, "0") != 0; +} - const char* webkit_load_event_to_string(WebKitLoadEvent event) { - switch (event) { - case WEBKIT_LOAD_STARTED: - return "started"; - case WEBKIT_LOAD_REDIRECTED: - return "redirected"; - case WEBKIT_LOAD_COMMITTED: - return "committed"; - case WEBKIT_LOAD_FINISHED: - return "finished"; - default: - return "unknown"; - } +const char* webkit_load_event_to_string(WebKitLoadEvent event) { + switch (event) { + case WEBKIT_LOAD_STARTED: + return "started"; + case WEBKIT_LOAD_REDIRECTED: + return "redirected"; + case WEBKIT_LOAD_COMMITTED: + return "committed"; + case WEBKIT_LOAD_FINISHED: + return "finished"; + default: + return "unknown"; } +} - const char* webkit_termination_reason_to_string(WebKitWebProcessTerminationReason reason) { - switch (reason) { - case WEBKIT_WEB_PROCESS_CRASHED: - return "crashed"; - case WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: - return "exceeded-memory-limit"; - case WEBKIT_WEB_PROCESS_TERMINATED_BY_API: - return "terminated-by-api"; - default: - return "unknown"; - } +const char* webkit_termination_reason_to_string(WebKitWebProcessTerminationReason reason) { + switch (reason) { + case WEBKIT_WEB_PROCESS_CRASHED: + return "crashed"; + case WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: + return "exceeded-memory-limit"; + case WEBKIT_WEB_PROCESS_TERMINATED_BY_API: + return "terminated-by-api"; + default: + return "unknown"; } } +} // namespace void InfiniFrameWindow::OnConfigureEvent(int x, int y, int width, int height) { if (m_impl->_lastLeft != x || m_impl->_lastTop != y) { @@ -56,11 +56,9 @@ void InfiniFrameWindow::OnConfigureEvent(int x, int y, int width, int height) { void InfiniFrameWindow::OnWindowStateEvent(GdkWindowState newState) { if (newState & GDK_WINDOW_STATE_MAXIMIZED) { InvokeMaximized(); - } - else if ((newState & GDK_WINDOW_STATE_ICONIFIED) || !gtk_widget_get_mapped(m_impl->_window)) { + } else if ((newState & GDK_WINDOW_STATE_ICONIFIED) || !gtk_widget_get_mapped(m_impl->_window)) { InvokeMinimized(); - } - else if (!(newState & GDK_WINDOW_STATE_MAXIMIZED) && !(newState & GDK_WINDOW_STATE_ICONIFIED)) { + } else if (!(newState & GDK_WINDOW_STATE_MAXIMIZED) && !(newState & GDK_WINDOW_STATE_ICONIFIED)) { InvokeRestored(); } } @@ -69,9 +67,8 @@ gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, const gpointer s if (event->type == GDK_CONFIGURE) { auto* instance = reinterpret_cast(self); instance->OnConfigureEvent( - event->configure.x, event->configure.y, - event->configure.width, event->configure.height - ); + event->configure.x, event->configure.y, event->configure.width, event->configure.height + ); } return FALSE; } @@ -110,7 +107,7 @@ gboolean on_webview_context_menu( WebKitHitTestResult* hit_test_result, gboolean triggered_with_keyboard, const gpointer self - ) { +) { auto* instance = reinterpret_cast(self); bool contextMenuEnabled = false; instance->GetContextMenuEnabled(&contextMenuEnabled); @@ -134,40 +131,30 @@ void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event const char* uri = webkit_web_view_get_uri(web_view); g_message( - "[InfiniFrame/Linux] WebKit load-changed: event=%s uri=%s", - webkit_load_event_to_string(load_event), + "[InfiniFrame/Linux] WebKit load-changed: event=%s uri=%s", webkit_load_event_to_string(load_event), uri ? uri : "" - ); + ); } gboolean on_webview_load_failed( - WebKitWebView* web_view, - WebKitLoadEvent load_event, - gchar* failing_uri, - GError* error, - gpointer user_data - ) { + WebKitWebView* web_view, WebKitLoadEvent load_event, gchar* failing_uri, GError* error, gpointer user_data +) { if (!linux_webview_diagnostics_enabled()) return FALSE; g_warning( - "[InfiniFrame/Linux] WebKit load-failed: event=%s uri=%s error=%s", - webkit_load_event_to_string(load_event), - failing_uri ? failing_uri : "", - error ? error->message : "" - ); + "[InfiniFrame/Linux] WebKit load-failed: event=%s uri=%s error=%s", webkit_load_event_to_string(load_event), + failing_uri ? failing_uri : "", error ? error->message : "" + ); return FALSE; } void on_webview_process_terminated( - WebKitWebView* web_view, - WebKitWebProcessTerminationReason reason, - gpointer user_data - ) { + WebKitWebView* web_view, WebKitWebProcessTerminationReason reason, gpointer user_data +) { g_warning( - "[InfiniFrame/Linux] WebKit web process terminated: reason=%s", - webkit_termination_reason_to_string(reason) - ); + "[InfiniFrame/Linux] WebKit web process terminated: reason=%s", webkit_termination_reason_to_string(reason) + ); } void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data) { @@ -175,10 +162,9 @@ void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpoi return; g_message( - "[InfiniFrame/Linux] WebView size-allocate: %dx%d", - allocation ? allocation->width : -1, + "[InfiniFrame/Linux] WebView size-allocate: %dx%d", allocation ? allocation->width : -1, allocation ? allocation->height : -1 - ); + ); } #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp index 0d530ce82..8173f35e8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp @@ -205,14 +205,7 @@ void InfiniFrameWindow::SendWebMessage(const AutoString message) { js.append("\")"); webkit_web_view_evaluate_javascript( - WEBKIT_WEB_VIEW(m_impl->_webview), - js.c_str(), - -1, - nullptr, - nullptr, - nullptr, - webview_eval_finished, - nullptr + WEBKIT_WEB_VIEW(m_impl->_webview), js.c_str(), -1, nullptr, nullptr, nullptr, webview_eval_finished, nullptr ); } @@ -273,9 +266,7 @@ void InfiniFrameWindow::SetMinSize(const int width, const int height) { m_impl->_hints.min_height = height; gtk_window_set_geometry_hints( - GTK_WINDOW(m_impl->_window), - nullptr, - &m_impl->_hints, + GTK_WINDOW(m_impl->_window), nullptr, &m_impl->_hints, static_cast(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE) ); } @@ -287,9 +278,7 @@ void InfiniFrameWindow::SetMaxSize(const int width, const int height) { m_impl->_hints.max_height = height; gtk_window_set_geometry_hints( - GTK_WINDOW(m_impl->_window), - nullptr, - &m_impl->_hints, + GTK_WINDOW(m_impl->_window), nullptr, &m_impl->_hints, static_cast(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE) ); } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp index 37a65a0dc..acee85cd7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp @@ -69,7 +69,7 @@ AutoString* ShowDialog( const int filterCount, int* resultCount, const AutoString defaultFileName = nullptr - ) { +) { GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; const char* buttonText = "_Open"; switch (type) { @@ -88,11 +88,8 @@ AutoString* ShowDialog( } GtkWidget* dialog = gtk_file_chooser_dialog_new( - title, nullptr, action, - "_Cancel", GTK_RESPONSE_CANCEL, - buttonText, GTK_RESPONSE_ACCEPT, - nullptr - ); + title, nullptr, action, "_Cancel", GTK_RESPONSE_CANCEL, buttonText, GTK_RESPONSE_ACCEPT, nullptr + ); if (defaultPath != nullptr) { gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), defaultPath); @@ -130,19 +127,16 @@ AutoString* ShowDialog( *resultCount = count; gtk_widget_destroy(dialog); return results; - } - else { + } else { char* result = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); gtk_widget_destroy(dialog); return new char*[1]{result}; } } -InfiniFrameDialog::InfiniFrameDialog() { -} +InfiniFrameDialog::InfiniFrameDialog() {} -InfiniFrameDialog::~InfiniFrameDialog() { -} +InfiniFrameDialog::~InfiniFrameDialog() {} AutoString* InfiniFrameDialog::ShowOpenFile( const AutoString title, @@ -151,16 +145,13 @@ AutoString* InfiniFrameDialog::ShowOpenFile( AutoString* filters, const int filterCount, int* resultCount - ) { +) { return ShowDialog(OpenFile, title, defaultPath, multiSelect, filters, filterCount, resultCount); } AutoString* InfiniFrameDialog::ShowOpenFolder( - const AutoString title, - const AutoString defaultPath, - const bool multiSelect, - int* resultCount - ) { + const AutoString title, const AutoString defaultPath, const bool multiSelect, int* resultCount +) { return ShowDialog(OpenFolder, title, defaultPath, multiSelect, nullptr, 0, resultCount); } @@ -170,7 +161,7 @@ AutoString InfiniFrameDialog::ShowSaveFile( AutoString* filters, const int filterCount, const AutoString defaultFileName - ) { +) { char** result = ShowDialog(SaveFile, title, defaultPath, false, filters, filterCount, nullptr, defaultFileName); if (result != nullptr) { char* value = result[0]; @@ -181,11 +172,8 @@ AutoString InfiniFrameDialog::ShowSaveFile( } DialogResult InfiniFrameDialog::ShowMessage( - const AutoString title, - const AutoString text, - const DialogButtons buttons, - const DialogIcon icon - ) { + const AutoString title, const AutoString text, const DialogButtons buttons, const DialogIcon icon +) { GtkWidget* dialog; GtkMessageType type; @@ -207,14 +195,7 @@ DialogResult InfiniFrameDialog::ShowMessage( break; } - dialog = gtk_message_dialog_new( - nullptr, - GTK_DIALOG_MODAL, - type, - GTK_BUTTONS_NONE, - "%s", - title - ); + dialog = gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL, type, GTK_BUTTONS_NONE, "%s", title); gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), text); switch (buttons) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h index ffb94ce49..7ff7044b3 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h @@ -6,13 +6,9 @@ #include namespace gtk_webkit { - void HandleWebMessage( - WebKitUserContentManager* contentManager, - WebKitJavascriptResult* jsResult, - gpointer userData - ); +void HandleWebMessage(WebKitUserContentManager* contentManager, WebKitJavascriptResult* jsResult, gpointer userData); - void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, gpointer userData); -} +void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, gpointer userData); +} // namespace gtk_webkit #endif // INFINIFRAME_PLATFORM_LINUX_WEBKIT_GTK_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp index 4aa36a8f9..0914fe615 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp @@ -7,29 +7,27 @@ #include "WebKit.Gtk.Internal.h" namespace gtk_webkit { - void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { - WebResourceRequestedCallback webResourceRequestedCallback = reinterpret_cast( - user_data); - if (webResourceRequestedCallback == nullptr) { - GError* error = g_error_new_literal( - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "No custom scheme handler is registered."); - webkit_uri_scheme_request_finish_error(request, error); - g_error_free(error); - return; - } - - const gchar* uri = webkit_uri_scheme_request_get_uri(request); - int numBytes = 0; - AutoString contentType = nullptr; - void* dotNetResponse = webResourceRequestedCallback(const_cast(uri), &numBytes, &contentType); - GInputStream* stream = g_memory_input_stream_new_from_data(dotNetResponse, numBytes, nullptr); - webkit_uri_scheme_request_finish(request, reinterpret_cast(stream), -1, contentType); - g_object_unref(stream); - free(contentType); +void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { + WebResourceRequestedCallback webResourceRequestedCallback = + reinterpret_cast(user_data); + if (webResourceRequestedCallback == nullptr) { + GError* error = + g_error_new_literal(G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "No custom scheme handler is registered."); + webkit_uri_scheme_request_finish_error(request, error); + g_error_free(error); + return; } + + const gchar* uri = webkit_uri_scheme_request_get_uri(request); + int numBytes = 0; + AutoString contentType = nullptr; + void* dotNetResponse = webResourceRequestedCallback(const_cast(uri), &numBytes, &contentType); + GInputStream* stream = g_memory_input_stream_new_from_data(dotNetResponse, numBytes, nullptr); + webkit_uri_scheme_request_finish(request, reinterpret_cast(stream), -1, contentType); + g_object_unref(stream); + free(contentType); } +} // namespace gtk_webkit void InfiniFrameWindow::Impl::AddCustomSchemeHandlers() { if (_customSchemeCallback == nullptr) @@ -45,9 +43,8 @@ void InfiniFrameWindow::Impl::AddCustomSchemeHandlers() { webkit_web_context_register_uri_scheme( context, value.c_str(), reinterpret_cast(gtk_webkit::HandleCustomSchemeRequest), - reinterpret_cast(_customSchemeCallback), - nullptr - ); + reinterpret_cast(_customSchemeCallback), nullptr + ); } } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp index 8b2bb827e..ece2fbfc6 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp @@ -9,17 +9,11 @@ extern void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data); extern gboolean on_webview_load_failed( - WebKitWebView* web_view, - WebKitLoadEvent load_event, - gchar* failing_uri, - GError* error, - gpointer user_data - ); + WebKitWebView* web_view, WebKitLoadEvent load_event, gchar* failing_uri, GError* error, gpointer user_data +); extern void on_webview_process_terminated( - WebKitWebView* web_view, - WebKitWebProcessTerminationReason reason, - gpointer user_data - ); + WebKitWebView* web_view, WebKitWebProcessTerminationReason reason, gpointer user_data +); extern void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data); void InfiniFrameWindow::Show(bool isAlreadyShown) { @@ -38,39 +32,25 @@ void InfiniFrameWindow::Show(bool isAlreadyShown) { auto js = Embedded::InfiniFrameJsUtf8(); WebKitUserScript* script = webkit_user_script_new( - js.c_str(), - WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, - WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, - nullptr, + js.c_str(), WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, nullptr, nullptr ); - + webkit_user_content_manager_add_script(contentManager, script); webkit_user_script_unref(script); g_signal_connect( - contentManager, "script-message-received::infiniFrameInterop", - G_CALLBACK(gtk_webkit::HandleWebMessage), + contentManager, "script-message-received::infiniFrameInterop", G_CALLBACK(gtk_webkit::HandleWebMessage), reinterpret_cast(m_impl->_webMessageReceivedCallback) - ); + ); webkit_user_content_manager_register_script_message_handler(contentManager, "infiniFrameInterop"); + g_signal_connect(G_OBJECT(m_impl->_webview), "load-changed", G_CALLBACK(on_webview_load_changed), this); + g_signal_connect(G_OBJECT(m_impl->_webview), "load-failed", G_CALLBACK(on_webview_load_failed), this); g_signal_connect( - G_OBJECT(m_impl->_webview), "load-changed", - G_CALLBACK(on_webview_load_changed), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "load-failed", - G_CALLBACK(on_webview_load_failed), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "web-process-terminated", - G_CALLBACK(on_webview_process_terminated), this - ); - g_signal_connect( - G_OBJECT(m_impl->_webview), "size-allocate", - G_CALLBACK(on_webview_size_allocate), this - ); + G_OBJECT(m_impl->_webview), "web-process-terminated", G_CALLBACK(on_webview_process_terminated), this + ); + g_signal_connect(G_OBJECT(m_impl->_webview), "size-allocate", G_CALLBACK(on_webview_size_allocate), this); if (!m_impl->_startUrl.empty()) NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); @@ -80,7 +60,7 @@ void InfiniFrameWindow::Show(bool isAlreadyShown) { GtkWidget* dialog = gtk_message_dialog_new( nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Neither StartUrl nor StartString was specified" - ); + ); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); sigaction(SIGCHLD, &old_action, nullptr); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp index 1480f4fd7..dfc4c6f90 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp @@ -7,43 +7,41 @@ #include "WebKit.Gtk.Internal.h" namespace gtk_webkit { - void HandleWebMessage( - WebKitUserContentManager* contentManager, - WebKitJavascriptResult* jsResult, - const gpointer userData - ) { - JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); - if (jsc_value_is_string(jsValue)) { - AutoString str_value = jsc_value_to_string(jsValue); - WebMessageReceivedCallback callback = reinterpret_cast(userData); - AutoString originValue = nullptr; - - JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); - JSStringRef script = JSStringCreateWithUTF8CString("window.location.href"); - JSValueRef locationValue = JSEvaluateScript(context, script, nullptr, nullptr, 0, nullptr); - JSStringRelease(script); - - if (locationValue != nullptr) { - JSStringRef locationString = JSValueToStringCopy(context, locationValue, nullptr); - if (locationString != nullptr) { - size_t maxBytes = JSStringGetMaximumUTF8CStringSize(locationString); - originValue = static_cast(g_malloc(maxBytes)); - JSStringGetUTF8CString(locationString, originValue, maxBytes); - JSStringRelease(locationString); - } +void HandleWebMessage( + WebKitUserContentManager* contentManager, WebKitJavascriptResult* jsResult, const gpointer userData +) { + JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); + if (jsc_value_is_string(jsValue)) { + AutoString str_value = jsc_value_to_string(jsValue); + WebMessageReceivedCallback callback = reinterpret_cast(userData); + AutoString originValue = nullptr; + + JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); + JSStringRef script = JSStringCreateWithUTF8CString("window.location.href"); + JSValueRef locationValue = JSEvaluateScript(context, script, nullptr, nullptr, 0, nullptr); + JSStringRelease(script); + + if (locationValue != nullptr) { + JSStringRef locationString = JSValueToStringCopy(context, locationValue, nullptr); + if (locationString != nullptr) { + size_t maxBytes = JSStringGetMaximumUTF8CStringSize(locationString); + originValue = static_cast(g_malloc(maxBytes)); + JSStringGetUTF8CString(locationString, originValue, maxBytes); + JSStringRelease(locationString); } + } - if (callback != nullptr) { - callback(str_value, originValue); - } + if (callback != nullptr) { + callback(str_value, originValue); + } - if (originValue != nullptr) - g_free(originValue); + if (originValue != nullptr) + g_free(originValue); - g_free(str_value); - } - webkit_javascript_result_unref(jsResult); + g_free(str_value); } + webkit_javascript_result_unref(jsResult); } +} // namespace gtk_webkit #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp index eacfd60a8..2d2e20fd1 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp @@ -6,27 +6,19 @@ void InfiniFrameWindow::Impl::set_webkit_settings() { WebKitSettings* settings = webkit_settings_new_with_settings( - "allow_modal_dialogs", TRUE, - "allow_top_navigation_to_data_urls", TRUE, - "allow_universal_access_from_file_urls", TRUE, - "enable_back_forward_navigation_gestures", TRUE, - "enable_media_capabilities", TRUE, - "enable_mock_capture_devices", TRUE, - "enable_page_cache", TRUE, - "enable_webrtc", TRUE, + "allow_modal_dialogs", TRUE, "allow_top_navigation_to_data_urls", TRUE, "allow_universal_access_from_file_urls", + TRUE, "enable_back_forward_navigation_gestures", TRUE, "enable_media_capabilities", TRUE, + "enable_mock_capture_devices", TRUE, "enable_page_cache", TRUE, "enable_webrtc", TRUE, "javascript_can_open_windows_automatically", TRUE, - "allow_file_access_from_file_urls", _fileSystemAccessEnabled, - "disable_web_security", !_webSecurityEnabled, - "enable_developer_extras", _devToolsEnabled, - "enable_media_stream", _mediaStreamEnabled, - "enable_smooth_scrolling", _smoothScrollingEnabled, - "javascript_can_access_clipboard", _javascriptClipboardAccessEnabled, - "media_playback_requires_user_gesture", !_mediaAutoplayEnabled, - "user_agent", _userAgent.c_str(), + "allow_file_access_from_file_urls", _fileSystemAccessEnabled, "disable_web_security", !_webSecurityEnabled, + "enable_developer_extras", _devToolsEnabled, "enable_media_stream", _mediaStreamEnabled, + "enable_smooth_scrolling", _smoothScrollingEnabled, "javascript_can_access_clipboard", + _javascriptClipboardAccessEnabled, "media_playback_requires_user_gesture", !_mediaAutoplayEnabled, "user_agent", + _userAgent.c_str(), NULL - ); + ); if (!_browserControlInitParameters.empty()) set_webkit_customsettings(settings); @@ -79,8 +71,7 @@ void InfiniFrameWindow::Impl::set_webkit_customsettings(WebKitSettings* settings g_value_init(&propertyValue, G_TYPE_INT); g_value_set_int(&propertyValue, static_cast(intVal)); hasValidValue = true; - } - else { + } else { double doubleVal; if (value.get(doubleVal) == simdjson::SUCCESS) { g_value_init(&propertyValue, G_TYPE_DOUBLE); @@ -101,9 +92,7 @@ void InfiniFrameWindow::Impl::set_webkit_customsettings(WebKitSettings* settings g_free(propertyName); } - } - catch (const simdjson::simdjson_error&) { - } + } catch (const simdjson::simdjson_error&) {} } #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp index ee1d2da9b..e4ac702b7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp @@ -35,20 +35,15 @@ void InfiniFrameWindow::Invoke(ACTION callback) { auto* waitInfo = new InvokeWaitInfo(); if (!PostMessage( - m_impl->_hWnd, WM_USER_INVOKE, reinterpret_cast(callback), reinterpret_cast(waitInfo) + m_impl->_hWnd, WM_USER_INVOKE, reinterpret_cast(callback), reinterpret_cast(waitInfo) )) { delete waitInfo; return; } std::unique_lock uLock(waitInfo->mutex); - const bool completed = waitInfo->completionNotifier.wait_for( - uLock, - std::chrono::seconds(15), - [&] { - return waitInfo->isCompleted; - } - ); + const bool completed = + waitInfo->completionNotifier.wait_for(uLock, std::chrono::seconds(15), [&] { return waitInfo->isCompleted; }); if (!completed) { bool deleteWaitInfo = false; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp index e145a71a4..8db804df4 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp @@ -19,17 +19,11 @@ std::wstring Utf8ToWide(const AutoString source) { return {}; std::u16string utf16(simdutf::utf16_length_from_utf8(utf8, utf8Length), u'\0'); - const size_t written = simdutf::convert_valid_utf8_to_utf16( - utf8, - utf8Length, - reinterpret_cast(utf16.data()) - ); + const size_t written = + simdutf::convert_valid_utf8_to_utf16(utf8, utf8Length, reinterpret_cast(utf16.data())); utf16.resize(written); - return { - reinterpret_cast(utf16.data()), - utf16.size() - }; + return {reinterpret_cast(utf16.data()), utf16.size()}; } std::string WideToUtf8(const AutoString source) { @@ -45,11 +39,7 @@ std::string WideToUtf8(const AutoString source) { return {}; std::string utf8(simdutf::utf8_length_from_utf16(utf16, utf16Length), '\0'); - const size_t written = simdutf::convert_valid_utf16_to_utf8( - utf16, - utf16Length, - utf8.data() - ); + const size_t written = simdutf::convert_valid_utf16_to_utf8(utf16, utf16Length, utf8.data()); utf8.resize(written); return utf8; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp index f4a5e9e97..f23b8b632 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp @@ -26,7 +26,8 @@ void InfiniFrameWindow::ShowNotification(AutoString title, AutoString body) { std::wstring wideTitle = ToUTF16String(title); std::wstring wideBody = ToUTF16String(body); if (m_impl->_notificationsEnabled && WinToastLib::WinToast::isCompatible()) { - WinToastLib::WinToastTemplate toast = WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::ImageAndText02); + WinToastLib::WinToastTemplate toast = + WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::ImageAndText02); toast.setTextField(wideTitle.c_str(), WinToastLib::WinToastTemplate::FirstLine); toast.setTextField(wideBody.c_str(), WinToastLib::WinToastTemplate::SecondLine); if (!m_impl->_iconFileName.empty()) @@ -38,8 +39,7 @@ void InfiniFrameWindow::ShowNotification(AutoString title, AutoString body) { void InfiniFrameWindow::GetAllMonitors(GetAllMonitorsCallback callback) const { if (callback) { EnumDisplayMonitors( - nullptr, nullptr, reinterpret_cast(MonitorEnum), - reinterpret_cast(callback) + nullptr, nullptr, reinterpret_cast(MonitorEnum), reinterpret_cast(callback) ); } } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp index 540582a21..9d4353421 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp @@ -8,40 +8,40 @@ using namespace WinToastLib; LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); namespace { - class BrushManager { - public: - static BrushManager& instance() noexcept { - static BrushManager inst; - return inst; - } - - HBRUSH dark() const noexcept { - return static_cast(m_darkBrush.get()); - } - - HBRUSH light() const noexcept { - return static_cast(m_lightBrush.get()); - } - - private: - BrushManager() noexcept { - m_darkBrush.reset(CreateSolidBrush(RGB(0, 0, 0))); - m_lightBrush.reset(CreateSolidBrush(RGB(255, 255, 255))); - } - - ~BrushManager() noexcept = default; - - struct HBRUSHDeleter { - void operator()(void* h) const noexcept { - if (h) - DeleteObject(static_cast(h)); - } - }; - - std::unique_ptr m_darkBrush; - std::unique_ptr m_lightBrush; +class BrushManager { +public: + static BrushManager& instance() noexcept { + static BrushManager inst; + return inst; + } + + HBRUSH dark() const noexcept { + return static_cast(m_darkBrush.get()); + } + + HBRUSH light() const noexcept { + return static_cast(m_lightBrush.get()); + } + +private: + BrushManager() noexcept { + m_darkBrush.reset(CreateSolidBrush(RGB(0, 0, 0))); + m_lightBrush.reset(CreateSolidBrush(RGB(255, 255, 255))); + } + + ~BrushManager() noexcept = default; + + struct HBRUSHDeleter { + void operator()(void* h) const noexcept { + if (h) + DeleteObject(static_cast(h)); + } }; -} + + std::unique_ptr m_darkBrush; + std::unique_ptr m_lightBrush; +}; +} // namespace HBRUSH GetDarkBrush() { return BrushManager::instance().dark(); @@ -79,9 +79,9 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { m_impl = std::make_unique(); if (initParams->Size != sizeof(InfiniFrameInitParams)) { auto msg = std::format( - L"Initial parameters passed are {} bytes, but expected {} bytes.", - initParams->Size, sizeof(InfiniFrameInitParams) - ); + L"Initial parameters passed are {} bytes, but expected {} bytes.", initParams->Size, + sizeof(InfiniFrameInitParams) + ); MessageBox(nullptr, msg.c_str(), L"Native Initialization Failed", MB_OK); exit(0); } @@ -113,7 +113,6 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { if (initParams->NotificationRegistrationId != nullptr) m_impl->_notificationRegistrationId = ToUTF16String(initParams->NotificationRegistrationId); - m_impl->_transparentEnabled = initParams->Transparent; m_impl->_contextMenuEnabled = initParams->ContextMenuEnabled; m_impl->_zoomEnabled = initParams->ZoomEnabled; @@ -162,8 +161,7 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { if (initParams->UseOsDefaultSize) { normalizedWidth = CW_USEDEFAULT; normalizedHeight = CW_USEDEFAULT; - } - else { + } else { if (normalizedWidth < 0) normalizedWidth = CW_USEDEFAULT; if (normalizedHeight < 0) @@ -204,22 +202,15 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { if (normalizedWidth < initParams->MinWidth && initParams->MinWidth > 0) normalizedWidth = initParams->MinWidth; - const HWND parentWindowHandle = ResolveParentWindowHandle(m_impl->_parent); m_impl->_pendingOwnerHwnd = parentWindowHandle; const HINSTANCE windowInstance = _hInstance.load(std::memory_order_acquire); m_impl->_hWnd = CreateWindowEx( - initParams->Transparent ? WS_EX_LAYERED : 0, - CLASS_NAME, - m_impl->_windowTitle.c_str(), - initParams->Chromeless || initParams->FullScreen ? WS_POPUP : WS_OVERLAPPEDWINDOW, - normalizedLeft, normalizedTop, normalizedWidth, normalizedHeight, - nullptr, - nullptr, - windowInstance, - this - ); + initParams->Transparent ? WS_EX_LAYERED : 0, CLASS_NAME, m_impl->_windowTitle.c_str(), + initParams->Chromeless || initParams->FullScreen ? WS_POPUP : WS_OVERLAPPEDWINDOW, normalizedLeft, + normalizedTop, normalizedWidth, normalizedHeight, nullptr, nullptr, windowInstance, this + ); ApplyPendingOwnerWindow(m_impl.get(), L"ctor"); @@ -227,7 +218,6 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { SetIconFile(initParams->WindowIconFile); } - if (centerOnInitialize) Center(); @@ -256,8 +246,7 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { Show(isAlreadyShown); } -InfiniFrameWindow::~InfiniFrameWindow() { -} +InfiniFrameWindow::~InfiniFrameWindow() {} HWND InfiniFrameWindow::getHwnd() { return m_impl->_hWnd; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp index a4696078b..0e10e21e5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp @@ -19,14 +19,9 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara RECT* newWindowRect = reinterpret_cast(lParam); SetWindowPos( - hwnd, - nullptr, - newWindowRect->left, - newWindowRect->top, - newWindowRect->right - newWindowRect->left, - newWindowRect->bottom - newWindowRect->top, - SWP_NOZORDER | SWP_NOACTIVATE - ); + hwnd, nullptr, newWindowRect->left, newWindowRect->top, newWindowRect->right - newWindowRect->left, + newWindowRect->bottom - newWindowRect->top, SWP_NOZORDER | SWP_NOACTIVATE + ); return 0; } @@ -48,8 +43,7 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara if (IsDarkModeEnabled()) { FillRect(hdc, &ps.rcPaint, GetDarkBrush()); - } - else { + } else { FillRect(hdc, &ps.rcPaint, GetLightBrush()); } @@ -57,12 +51,11 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara break; } case WM_ACTIVATE: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); + InfiniFrameWindow* instance = LookupWindowInstance(hwnd); if (instance) { if (LOWORD(wParam) == WA_INACTIVE) { instance->InvokeFocusOut(); - } - else { + } else { instance->FocusWebView2(); instance->InvokeFocusIn(); @@ -72,7 +65,7 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara break; } case WM_CLOSE: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); + InfiniFrameWindow* instance = LookupWindowInstance(hwnd); if (instance) { TraceTeardown(L"WM_CLOSE hwnd=%p instance=%p", hwnd, instance); bool doNotClose = instance->InvokeClose(); @@ -83,11 +76,9 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara const DWORD ownerDetachError = GetLastError(); if (previousOwner != 0 || ownerDetachError == 0) { TraceTeardown( - L"WM_CLOSE detached owner hwnd=%p prevOwner=%p err=%lu", - hwnd, - reinterpret_cast(previousOwner), - ownerDetachError - ); + L"WM_CLOSE detached owner hwnd=%p prevOwner=%p err=%lu", hwnd, + reinterpret_cast(previousOwner), ownerDetachError + ); } DestroyWindow(hwnd); @@ -97,7 +88,7 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara return 0; } case WM_DESTROY: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); + InfiniFrameWindow* instance = LookupWindowInstance(hwnd); if (instance) { instance->m_impl->_isClosingOrClosed.store(true, std::memory_order_release); TraceTeardown(L"WM_DESTROY begin hwnd=%p instance=%p", hwnd, instance); @@ -111,7 +102,7 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara return 0; } case WM_NCDESTROY: { - InfiniFrameWindow * instance = LookupWindowInstance(hwnd); + InfiniFrameWindow* instance = LookupWindowInstance(hwnd); if (instance) { instance->m_impl->_isClosingOrClosed.store(true, std::memory_order_release); instance->m_impl->_hWnd = nullptr; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp index eb590caaf..e60595b7f 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp @@ -293,14 +293,12 @@ void InfiniFrameWindow::SetFullScreen(const bool fullScreen) { if (GetMonitorInfoW(monitor, &monitorInfo)) { RECT rc = monitorInfo.rcMonitor; SetWindowPos( - m_impl->_hWnd, HWND_TOP, - rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, + m_impl->_hWnd, HWND_TOP, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOOWNERZORDER ); } else { SetWindowPos( - m_impl->_hWnd, HWND_TOP, - 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), + m_impl->_hWnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED | SWP_NOOWNERZORDER ); } @@ -312,8 +310,7 @@ void InfiniFrameWindow::SetFullScreen(const bool fullScreen) { if (m_impl->_hasSavedRect) { RECT& r = m_impl->_savedRect; SetWindowPos( - m_impl->_hWnd, HWND_TOP, - r.left, r.top, r.right - r.left, r.bottom - r.top, + m_impl->_hWnd, HWND_TOP, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_FRAMECHANGED | SWP_NOOWNERZORDER ); m_impl->_hasSavedRect = false; @@ -327,16 +324,12 @@ void InfiniFrameWindow::SetIconFile(const AutoString filename) { if (wideFilename.empty()) return; - HICON iconSmall = static_cast(LoadImageW( - nullptr, wideFilename.c_str(), - IMAGE_ICON, 16, 16, - LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED - )); - HICON iconBig = static_cast(LoadImageW( - nullptr, wideFilename.c_str(), - IMAGE_ICON, 32, 32, - LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED - )); + HICON iconSmall = static_cast( + LoadImageW(nullptr, wideFilename.c_str(), IMAGE_ICON, 16, 16, LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED) + ); + HICON iconBig = static_cast( + LoadImageW(nullptr, wideFilename.c_str(), IMAGE_ICON, 32, 32, LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED) + ); if (iconSmall && iconBig) { SendMessageW(m_impl->_hWnd, WM_SETICON, ICON_SMALL, reinterpret_cast(iconSmall)); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp index f1d31bb75..c79c407ed 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp @@ -13,25 +13,16 @@ bool EnsureDirectoryWritable(const std::wstring& directoryPath) { return false; const std::wstring probePath = std::format( - L"{}\\{}.tmp", - directoryPath, + L"{}\\{}.tmp", directoryPath, std::format( - L".infiniframe-wv2-write-check-{}-{}-{}", - GetCurrentProcessId(), - GetCurrentThreadId(), - GetTickCount64() - ) - ); + L".infiniframe-wv2-write-check-{}-{}-{}", GetCurrentProcessId(), GetCurrentThreadId(), GetTickCount64() + ) + ); HANDLE probeHandle = CreateFileW( - probePath.c_str(), - GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, - CREATE_ALWAYS, - FILE_ATTRIBUTE_TEMPORARY, - nullptr - ); + probePath.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, + CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, nullptr + ); if (probeHandle == INVALID_HANDLE_VALUE) return false; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp index b4fb2efe5..86343bc59 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp @@ -12,10 +12,8 @@ bool IsTeardownTraceEnabled() { if (len == 0 || len >= _countof(value)) return false; - return _wcsicmp(value, L"1") == 0 - || _wcsicmp(value, L"true") == 0 - || _wcsicmp(value, L"yes") == 0 - || _wcsicmp(value, L"on") == 0; + return _wcsicmp(value, L"1") == 0 || _wcsicmp(value, L"true") == 0 || _wcsicmp(value, L"yes") == 0 || + _wcsicmp(value, L"on") == 0; }(); return enabled; @@ -31,11 +29,7 @@ void TraceTeardown(const wchar_t* format, ...) { _vsnwprintf_s(message, _countof(message), _TRUNCATE, format, args); va_end(args); - const std::wstring line = std::format( - L"[InfiniFrame][teardown][tid={}] {}\n", - GetCurrentThreadId(), - message - ); + const std::wstring line = std::format(L"[InfiniFrame][teardown][tid={}] {}\n", GetCurrentThreadId(), message); OutputDebugStringW(line.c_str()); std::fwprintf(stderr, L"%ls", line.c_str()); std::fflush(stderr); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp index 0dc18ec50..1f75ca4f7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp @@ -4,8 +4,7 @@ using RtlGetNtVersionNumbers_f = void(WINAPI*)(LPDWORD, LPDWORD, LPDWORD); -using SetWindowCompositionAttribute_f = -HRESULT(WINAPI*)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); +using SetWindowCompositionAttribute_f = HRESULT(WINAPI*)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); using ShouldAppsUseDarkMode_f = BOOLEAN(WINAPI*)(); @@ -15,197 +14,169 @@ using RefreshImmersiveColorPolicyState_f = void(WINAPI*)(); using IsDarkModeAllowedForWindow_f = BOOLEAN(WINAPI*)(HWND); -using GetIsImmersiveColorUsingHighContrast_f = -BOOLEAN(WINAPI*)(IMMERSIVE_HC_CACHE_MODE); +using GetIsImmersiveColorUsingHighContrast_f = BOOLEAN(WINAPI*)(IMMERSIVE_HC_CACHE_MODE); using SetPreferredAppMode_f = PreferredAppMode(WINAPI*)(PreferredAppMode); -static SetWindowCompositionAttribute_f SetWindowCompositionAttribute = nullptr; -static ShouldAppsUseDarkMode_f ShouldAppsUseDarkMode = nullptr; -static AllowDarkModeForWindow_f AllowDarkModeForWindow = nullptr; -static RefreshImmersiveColorPolicyState_f RefreshImmersiveColorPolicyState = - nullptr; -static IsDarkModeAllowedForWindow_f IsDarkModeAllowedForWindow = nullptr; -static GetIsImmersiveColorUsingHighContrast_f -GetIsImmersiveColorUsingHighContrast = nullptr; -static SetPreferredAppMode_f SetPreferredAppMode = nullptr; +static SetWindowCompositionAttribute_f setWindowCompositionAttribute = nullptr; +static ShouldAppsUseDarkMode_f shouldAppsUseDarkMode = nullptr; +static AllowDarkModeForWindow_f allowDarkModeForWindow = nullptr; +static RefreshImmersiveColorPolicyState_f refreshImmersiveColorPolicyState = nullptr; +static IsDarkModeAllowedForWindow_f isDarkModeAllowedForWindow = nullptr; +static GetIsImmersiveColorUsingHighContrast_f getIsImmersiveColorUsingHighContrast = nullptr; +static SetPreferredAppMode_f setPreferredAppMode = nullptr; -static constexpr DWORD WIN10_MINIMUM_BUILD_DARK_MODE = 18362; +static constexpr DWORD wiN10MinimumBuildDarkMode = 18362; -static std::once_flag flag_init_dark_mode_support; +static std::once_flag flagInitDarkModeSupport; namespace { - class ModuleHandle { - public: - ~ModuleHandle() { - if (_handle != nullptr) { - FreeLibrary(_handle); - } - } - - void reset(HMODULE handle) { - if (_handle != nullptr) { - FreeLibrary(_handle); - } - _handle = handle; - } - - HMODULE get() const { - return _handle; - } - - private: - HMODULE _handle = nullptr; - }; - - ModuleHandle g_uxtheme; -} +class ModuleHandle { +public: + ~ModuleHandle() { + if (_handle != nullptr) { + FreeLibrary(_handle); + } + } + + void reset(HMODULE handle) { + if (_handle != nullptr) { + FreeLibrary(_handle); + } + _handle = handle; + } + + auto get() const -> HMODULE { + return _handle; + } + +private: + HMODULE _handle = nullptr; +}; + +ModuleHandle gUxtheme; +} // namespace static void EnableDarkModeForApp() noexcept { - if (SetPreferredAppMode != nullptr) { - SetPreferredAppMode(AllowDark); + if (setPreferredAppMode != nullptr) { + setPreferredAppMode(AllowDark); } } -[[nodiscard]] static DWORD GetBuildNumber() noexcept { - auto RtlGetNtVersionNumbers = - reinterpret_cast(GetProcAddress( - GetModuleHandleW(L"ntdll.dll"), "RtlGetNtVersionNumbers" - )); +[[nodiscard]] static auto GetBuildNumber() noexcept -> DWORD { + auto rtlGetNtVersionNumbers = reinterpret_cast( + GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetNtVersionNumbers") + ); - if (RtlGetNtVersionNumbers == nullptr) { + if (rtlGetNtVersionNumbers == nullptr) { return 0; } DWORD major = 0; DWORD minor = 0; DWORD build = 0; - RtlGetNtVersionNumbers(&major, &minor, &build); + rtlGetNtVersionNumbers(&major, &minor, &build); build &= ~0xF0000000; return build; } -[[nodiscard]] static bool IsHighContrast() noexcept { - HIGHCONTRASTW high_contrast; - high_contrast.cbSize = sizeof(high_contrast); - if (SystemParametersInfoW( - SPI_GETHIGHCONTRAST, - sizeof(high_contrast), - &high_contrast, - FALSE - ) == TRUE) { - return (high_contrast.dwFlags & HCF_HIGHCONTRASTON) > 0; +[[nodiscard]] static auto IsHighContrast() noexcept -> bool { + HIGHCONTRASTW highContrast; + highContrast.cbSize = sizeof(highContrast); + if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE) == TRUE) { + return (highContrast.dwFlags & HCF_HIGHCONTRASTON) > 0; } return false; } static void InitDarkModeSupportOnce() noexcept { - const auto build_number = GetBuildNumber(); + const auto buildNumber = GetBuildNumber(); - if (build_number < WIN10_MINIMUM_BUILD_DARK_MODE) { + if (buildNumber < wiN10MinimumBuildDarkMode) { return; } - g_uxtheme.reset( - LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) - ); + gUxtheme.reset(LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)); - if (g_uxtheme.get() == nullptr) { + if (gUxtheme.get() == nullptr) { return; } - RefreshImmersiveColorPolicyState = - reinterpret_cast( - GetProcAddress(g_uxtheme.get(), MAKEINTRESOURCEA(104))); + refreshImmersiveColorPolicyState = + reinterpret_cast(GetProcAddress(gUxtheme.get(), MAKEINTRESOURCEA(104))); - GetIsImmersiveColorUsingHighContrast = - reinterpret_cast( - GetProcAddress(g_uxtheme.get(), MAKEINTRESOURCEA(106))); + getIsImmersiveColorUsingHighContrast = + reinterpret_cast(GetProcAddress(gUxtheme.get(), MAKEINTRESOURCEA(106))); - ShouldAppsUseDarkMode = reinterpret_cast( - GetProcAddress(g_uxtheme.get(), MAKEINTRESOURCEA(132))); + shouldAppsUseDarkMode = + reinterpret_cast(GetProcAddress(gUxtheme.get(), MAKEINTRESOURCEA(132))); - AllowDarkModeForWindow = reinterpret_cast( - GetProcAddress(g_uxtheme.get(), MAKEINTRESOURCEA(133))); + allowDarkModeForWindow = + reinterpret_cast(GetProcAddress(gUxtheme.get(), MAKEINTRESOURCEA(133))); - SetPreferredAppMode = reinterpret_cast( - GetProcAddress(g_uxtheme.get(), MAKEINTRESOURCEA(135))); + setPreferredAppMode = + reinterpret_cast(GetProcAddress(gUxtheme.get(), MAKEINTRESOURCEA(135))); - IsDarkModeAllowedForWindow = - reinterpret_cast( - GetProcAddress(g_uxtheme.get(), MAKEINTRESOURCEA(137))); + isDarkModeAllowedForWindow = + reinterpret_cast(GetProcAddress(gUxtheme.get(), MAKEINTRESOURCEA(137))); - SetWindowCompositionAttribute = - reinterpret_cast(GetProcAddress( - GetModuleHandleW(L"user32.dll"), "SetWindowCompositionAttribute" - )); + setWindowCompositionAttribute = reinterpret_cast( + GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetWindowCompositionAttribute") + ); - if (RefreshImmersiveColorPolicyState != nullptr && - ShouldAppsUseDarkMode != nullptr && - AllowDarkModeForWindow != nullptr && SetPreferredAppMode != nullptr && - IsDarkModeAllowedForWindow != nullptr) { + if (refreshImmersiveColorPolicyState != nullptr && shouldAppsUseDarkMode != nullptr && + allowDarkModeForWindow != nullptr && setPreferredAppMode != nullptr && isDarkModeAllowedForWindow != nullptr) { EnableDarkModeForApp(); - RefreshImmersiveColorPolicyState(); + refreshImmersiveColorPolicyState(); } } void InitDarkModeSupport() noexcept { - std::call_once(flag_init_dark_mode_support, InitDarkModeSupportOnce); + std::call_once(flagInitDarkModeSupport, InitDarkModeSupportOnce); } -bool IsDarkModeEnabled() noexcept { - if (ShouldAppsUseDarkMode == nullptr) { +auto IsDarkModeEnabled() noexcept -> bool { + if (shouldAppsUseDarkMode == nullptr) { return false; } - return (ShouldAppsUseDarkMode() == TRUE) && !IsHighContrast(); + return (shouldAppsUseDarkMode() == TRUE) && !IsHighContrast(); } void EnableDarkMode(const HWND hwnd, const bool enable) noexcept { - if (AllowDarkModeForWindow == nullptr) { + if (allowDarkModeForWindow == nullptr) { return; } - AllowDarkModeForWindow(hwnd, enable ? TRUE : FALSE); + allowDarkModeForWindow(hwnd, enable ? TRUE : FALSE); } void RefreshNonClientArea(const HWND hwnd) noexcept { - if (IsDarkModeAllowedForWindow == nullptr || - ShouldAppsUseDarkMode == nullptr) { + if (isDarkModeAllowedForWindow == nullptr || shouldAppsUseDarkMode == nullptr) { return; } BOOL dark = FALSE; - if (IsDarkModeAllowedForWindow(hwnd) == TRUE && - ShouldAppsUseDarkMode() == TRUE && !IsHighContrast()) { + if (isDarkModeAllowedForWindow(hwnd) == TRUE && shouldAppsUseDarkMode() == TRUE && !IsHighContrast()) { dark = TRUE; } - if (SetWindowCompositionAttribute != nullptr) { - WINDOWCOMPOSITIONATTRIBDATA data = { - WCA_USEDARKMODECOLORS, - &dark, - sizeof(dark) - }; - SetWindowCompositionAttribute(hwnd, &data); + if (setWindowCompositionAttribute != nullptr) { + WINDOWCOMPOSITIONATTRIBDATA data = {WCA_USEDARKMODECOLORS, &dark, sizeof(dark)}; + setWindowCompositionAttribute(hwnd, &data); } } -bool IsColorSchemeChange(const LPARAM l_param) noexcept { - bool return_value = false; - if (l_param > 0 && CompareStringOrdinal( - reinterpret_cast(l_param), - -1, - L"ImmersiveColorSet", - -1, - TRUE - ) == CSTR_EQUAL) { - if (RefreshImmersiveColorPolicyState != nullptr) { - RefreshImmersiveColorPolicyState(); +auto IsColorSchemeChange(const LPARAM lParam) noexcept -> bool { + bool returnValue = false; + if (lParam > 0 && + CompareStringOrdinal(reinterpret_cast(lParam), -1, L"ImmersiveColorSet", -1, TRUE) == CSTR_EQUAL) { + if (refreshImmersiveColorPolicyState != nullptr) { + refreshImmersiveColorPolicyState(); } - return_value = true; + returnValue = true; } - if (GetIsImmersiveColorUsingHighContrast != nullptr) { - GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH); + if (getIsImmersiveColorUsingHighContrast != nullptr) { + getIsImmersiveColorUsingHighContrast(IHCM_REFRESH); } - return return_value; + return returnValue; } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h index 65c0cd3ee..c06657886 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h @@ -17,7 +17,7 @@ void InitDarkModeSupport() noexcept; * @brief Check whether the current Windows theme is dark * @return true if the system is in dark mode */ -[[nodiscard]] bool IsDarkModeEnabled() noexcept; +[[nodiscard]] auto IsDarkModeEnabled() noexcept -> bool; /** * @brief Apply or remove dark mode coloring on a window's non-client area @@ -38,7 +38,7 @@ void RefreshNonClientArea(HWND hwnd) noexcept; * @param l_param lParam from a WM_SETTINGCHANGE message * @return true if the message indicates an immersive color-scheme change */ -[[nodiscard]] bool IsColorSchemeChange(LPARAM l_param) noexcept; +[[nodiscard]] auto IsColorSchemeChange(LPARAM lParam) noexcept -> bool; // --------------------------------------------------------------------------------------------------------------------- // Internal UxTheme / DWM types (undocumented Win32 API surface) @@ -48,48 +48,48 @@ void RefreshNonClientArea(HWND hwnd) noexcept; /** @brief Controls whether the immersive color cache is used or refreshed */ enum IMMERSIVE_HC_CACHE_MODE { IHCM_USE_CACHED_VALUE = 0, /// Use the previously cached value - IHCM_REFRESH = 1, /// Force a refresh of the cached value + IHCM_REFRESH = 1, /// Force a refresh of the cached value }; /** @brief Application color-mode preference passed to SetPreferredAppMode */ enum PreferredAppMode { - Default = 0, /// Follow the system setting - AllowDark = 1, /// Allow dark mode if the system is dark - ForceDark = 2, /// Always use dark mode + Default = 0, /// Follow the system setting + AllowDark = 1, /// Allow dark mode if the system is dark + ForceDark = 2, /// Always use dark mode ForceLight = 3, /// Always use light mode - Max = 4, /// Sentinel value; not a valid mode + Max = 4, /// Sentinel value; not a valid mode }; /** @brief Window composition attribute identifiers used with SetWindowCompositionAttribute */ enum WINDOWCOMPOSITIONATTRIB { - WCA_UNDEFINED = 0, - WCA_NCRENDERING_ENABLED = 1, /// Non-client rendering enabled flag - WCA_NCRENDERING_POLICY = 2, /// Non-client rendering policy - WCA_TRANSITIONS_FORCEDISABLED = 3, - WCA_ALLOW_NCPAINT = 4, - WCA_CAPTION_BUTTON_BOUNDS = 5, - WCA_NONCLIENT_RTL_LAYOUT = 6, - WCA_FORCE_ICONIC_REPRESENTATION = 7, - WCA_EXTENDED_FRAME_BOUNDS = 8, - WCA_HAS_ICONIC_BITMAP = 9, - WCA_THEME_ATTRIBUTES = 10, - WCA_NCRENDERING_EXILED = 11, - WCA_NCADORNMENTINFO = 12, - WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, - WCA_VIDEO_OVERLAY_ACTIVE = 14, + WCA_UNDEFINED = 0, + WCA_NCRENDERING_ENABLED = 1, /// Non-client rendering enabled flag + WCA_NCRENDERING_POLICY = 2, /// Non-client rendering policy + WCA_TRANSITIONS_FORCEDISABLED = 3, + WCA_ALLOW_NCPAINT = 4, + WCA_CAPTION_BUTTON_BOUNDS = 5, + WCA_NONCLIENT_RTL_LAYOUT = 6, + WCA_FORCE_ICONIC_REPRESENTATION = 7, + WCA_EXTENDED_FRAME_BOUNDS = 8, + WCA_HAS_ICONIC_BITMAP = 9, + WCA_THEME_ATTRIBUTES = 10, + WCA_NCRENDERING_EXILED = 11, + WCA_NCADORNMENTINFO = 12, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, + WCA_VIDEO_OVERLAY_ACTIVE = 14, WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, - WCA_DISALLOW_PEEK = 16, - WCA_CLOAK = 17, - WCA_CLOAKED = 18, - WCA_ACCENT_POLICY = 19, - WCA_FREEZE_REPRESENTATION = 20, - WCA_EVER_UNCLOAKED = 21, - WCA_VISUAL_OWNER = 22, - WCA_HOLOGRAPHIC = 23, - WCA_EXCLUDED_FROM_DDA = 24, - WCA_PASSIVEUPDATEMODE = 25, - WCA_USEDARKMODECOLORS = 26, /// Enable dark mode colors for non-client area - WCA_LAST = 27, + WCA_DISALLOW_PEEK = 16, + WCA_CLOAK = 17, + WCA_CLOAKED = 18, + WCA_ACCENT_POLICY = 19, + WCA_FREEZE_REPRESENTATION = 20, + WCA_EVER_UNCLOAKED = 21, + WCA_VISUAL_OWNER = 22, + WCA_HOLOGRAPHIC = 23, + WCA_EXCLUDED_FROM_DDA = 24, + WCA_PASSIVEUPDATEMODE = 25, + WCA_USEDARKMODECOLORS = 26, /// Enable dark mode colors for non-client area + WCA_LAST = 27, }; /** @brief Parameter struct for SetWindowCompositionAttribute */ diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp index 2467ce3ca..644b73cc8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp @@ -17,49 +17,46 @@ * Used to ensure comdlg32 is available before activating the common-controls activation context */ class Dll { - public: - /** @brief Load the named DLL; handle is null if loading fails */ - explicit Dll(const std::string& name); - /** @brief Unload the DLL if it was loaded successfully */ - ~Dll(); +public: + /** @brief Load the named DLL; handle is null if loading fails */ + explicit Dll(const std::string& name); + /** @brief Unload the DLL if it was loaded successfully */ + ~Dll(); - /** + /** * @brief Type-safe wrapper around a single exported function retrieved via GetProcAddress * @tparam T Function signature (e.g. BOOL(HWND, LPCWSTR)) */ - template - class Proc { - public: - /** + template class Proc { + public: + /** * @brief Resolve a symbol from a loaded DLL * @param lib DLL to search * @param sym Exported symbol name */ - Proc(const Dll& lib, const std::string& sym) : - _mProc(static_cast(reinterpret_cast(GetProcAddress(lib._handle, sym.c_str())))) { - } - - /** @brief Returns true if the symbol was resolved successfully */ - explicit operator bool() const { - return _mProc != nullptr; - } + Proc(const Dll& lib, const std::string& sym) + : _mProc(static_cast(reinterpret_cast(GetProcAddress(lib._handle, sym.c_str())))) {} - /** @brief Returns the raw function pointer */ - explicit operator T*() const { - return _mProc; - } + /** @brief Returns true if the symbol was resolved successfully */ + explicit operator bool() const { + return _mProc != nullptr; + } - private: - T* _mProc; - }; + /** @brief Returns the raw function pointer */ + explicit operator T*() const { + return _mProc; + } private: - HMODULE _handle; + T* _mProc; + }; + +private: + HMODULE _handle; }; -inline Dll::Dll(const std::string& name) : - _handle(LoadLibraryA(name.c_str())) { -} +inline Dll::Dll(const std::string& name) + : _handle(LoadLibraryA(name.c_str())) {} inline Dll::~Dll() { if (_handle) @@ -74,26 +71,26 @@ inline Dll::~Dll() { * embedded manifest resource (ID 124) */ class NewStyleContext { - public: - /** @brief Activate the Common Controls v6 context */ - NewStyleContext(); - /** @brief Deactivate the context */ - ~NewStyleContext(); - - private: - /** @brief Create the activation context from shell32.dll's manifest; called once */ - static HANDLE Create(); - - struct ActivationContextHolder { - HANDLE handle = INVALID_HANDLE_VALUE; - - ~ActivationContextHolder() { - if (handle != INVALID_HANDLE_VALUE) - ReleaseActCtx(handle); - } - }; +public: + /** @brief Activate the Common Controls v6 context */ + NewStyleContext(); + /** @brief Deactivate the context */ + ~NewStyleContext(); + +private: + /** @brief Create the activation context from shell32.dll's manifest; called once */ + static HANDLE Create(); + + struct ActivationContextHolder { + HANDLE handle = INVALID_HANDLE_VALUE; + + ~ActivationContextHolder() { + if (handle != INVALID_HANDLE_VALUE) + ReleaseActCtx(handle); + } + }; - ULONG_PTR _cookie = 0; /// Activation cookie returned by ActivateActCtx; used to deactivate + ULONG_PTR _cookie = 0; /// Activation cookie returned by ActivateActCtx; used to deactivate }; inline NewStyleContext::NewStyleContext() { @@ -115,8 +112,7 @@ inline HANDLE NewStyleContext::Create() { std::string sysDir(len, '\0'); GetSystemDirectoryA(const_cast(sysDir.data()), len); - const ACTCTXA actCtx = - { + const ACTCTXA actCtx = { sizeof(actCtx), ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, "shell32.dll", @@ -148,15 +144,12 @@ InfiniFrameDialog::~InfiniFrameDialog() { * @param defaultPath UTF-16 path to pre-select as the starting folder; may be null * @return Pointer to the created dialog; caller owns the COM reference. Returns null on failure. */ -template -T* Create(HRESULT* hResult, AutoStringConst title, const AutoStringConst defaultPath) { +template T* Create(HRESULT* hResult, AutoStringConst title, const AutoStringConst defaultPath) { static_assert(std::is_base_of::value, "T must inherit from IFileDialog"); T* pfd = nullptr; - const CLSID clsid = typeid(T) == typeid(IFileOpenDialog) - ? CLSID_FileOpenDialog - : typeid(T) == typeid(IFileSaveDialog) - ? CLSID_FileSaveDialog - : CLSID_FileOpenDialog; + const CLSID clsid = typeid(T) == typeid(IFileOpenDialog) ? CLSID_FileOpenDialog + : typeid(T) == typeid(IFileSaveDialog) ? CLSID_FileSaveDialog + : CLSID_FileOpenDialog; HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd)); if (SUCCEEDED(hr)) { pfd->SetTitle(title); @@ -195,7 +188,7 @@ void AddFilters( const int filterCount, InfiniFrameWindow* wndInstance, std::vector& filterStorage - ) { +) { std::vector specs; for (int i = 0; i < filterCount; i++) { filterStorage.push_back(wndInstance->ToUTF16String(filters[i])); @@ -270,7 +263,7 @@ AutoString* InfiniFrameDialog::ShowOpenFile( AutoString* filters, const int filterCount, int* resultCount - ) { +) { HRESULT hr; std::wstring wideTitle = _window->ToUTF16String(title); std::wstring wideDefaultPath = _window->ToUTF16String(defaultPath); @@ -286,8 +279,7 @@ AutoString* InfiniFrameDialog::ShowOpenFile( dwOptions |= FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR; if (multiSelect) { dwOptions |= FOS_ALLOWMULTISELECT; - } - else { + } else { dwOptions &= ~FOS_ALLOWMULTISELECT; } pfd->SetOptions(dwOptions); @@ -302,11 +294,8 @@ AutoString* InfiniFrameDialog::ShowOpenFile( } AutoString* InfiniFrameDialog::ShowOpenFolder( - AutoString title, - AutoString defaultPath, - const bool multiSelect, - int* resultCount - ) { + AutoString title, AutoString defaultPath, const bool multiSelect, int* resultCount +) { HRESULT hr; std::wstring wideTitle = _window->ToUTF16String(title); std::wstring wideDefaultPath = _window->ToUTF16String(defaultPath); @@ -319,8 +308,7 @@ AutoString* InfiniFrameDialog::ShowOpenFolder( dwOptions |= FOS_PICKFOLDERS | FOS_NOCHANGEDIR; if (multiSelect) { dwOptions |= FOS_ALLOWMULTISELECT; - } - else { + } else { dwOptions &= ~FOS_ALLOWMULTISELECT; } pfd->SetOptions(dwOptions); @@ -335,12 +323,8 @@ AutoString* InfiniFrameDialog::ShowOpenFolder( } AutoString InfiniFrameDialog::ShowSaveFile( - AutoString title, - AutoString defaultPath, - AutoString* filters, - const int filterCount, - AutoString defaultFileName - ) { + AutoString title, AutoString defaultPath, AutoString* filters, const int filterCount, AutoString defaultFileName +) { HRESULT hr; std::wstring wideTitle = _window->ToUTF16String(title); std::wstring wideDefaultPath = _window->ToUTF16String(defaultPath); @@ -384,11 +368,8 @@ AutoString InfiniFrameDialog::ShowSaveFile( } DialogResult InfiniFrameDialog::ShowMessage( - AutoString title, - AutoString text, - const DialogButtons buttons, - const DialogIcon icon - ) { + AutoString title, AutoString text, const DialogButtons buttons, const DialogIcon icon +) { std::wstring wideTitle = _window->ToUTF16String(title); std::wstring wideText = _window->ToUTF16String(text); NewStyleContext ctx; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h index 578b0f206..8bb28d45d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h @@ -20,46 +20,43 @@ using namespace WinToastLib; class WinToastHandler final : public IWinToastHandler { InfiniFrameWindow* _window; - public: - /** +public: + /** * @brief Construct a handler bound to a specific window * @param window The window to bring to the foreground on notification activation */ - explicit WinToastHandler(InfiniFrameWindow* window) : - _window(window) { - } + explicit WinToastHandler(InfiniFrameWindow* window) + : _window(window) {} - /** @brief Called when the user clicks the notification body; restores and focuses the window */ - void toastActivated() const override { - ShowWindow(this->_window->getHwnd(), SW_SHOW); - ShowWindow(this->_window->getHwnd(), SW_RESTORE); - SetForegroundWindow(this->_window->getHwnd()); - } + /** @brief Called when the user clicks the notification body; restores and focuses the window */ + void toastActivated() const override { + ShowWindow(this->_window->getHwnd(), SW_SHOW); + ShowWindow(this->_window->getHwnd(), SW_RESTORE); + SetForegroundWindow(this->_window->getHwnd()); + } - /** + /** * @brief Called when the user clicks an action button on the notification * @param actionIndex Zero-based index of the activated button (unused; delegates to toastActivated()) */ - void toastActivated(int) const override { - toastActivated(); - } + void toastActivated(int) const override { + toastActivated(); + } - /** + /** * @brief Called when the user submits a text-input reply on the notification * @param response User-entered text (unused; delegates to toastActivated()) */ - void toastActivated(std::wstring) const override { - toastActivated(); - } + void toastActivated(std::wstring) const override { + toastActivated(); + } - /** + /** * @brief Called when the notification is dismissed without activation * @param state Reason for dismissal (timeout, user swipe, app hide, etc.) */ - void toastDismissed(WinToastDismissalReason) const override { - } + void toastDismissed(WinToastDismissalReason) const override {} - /** @brief Called when the notification fails to display */ - void toastFailed() const override { - } + /** @brief Called when the notification fails to display */ + void toastFailed() const override {} }; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp index 632225f16..07e0b90f2 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp @@ -67,12 +67,9 @@ void InfiniFrameWindow::AttachWebView() { options->put_AdditionalBrowserArguments(startupString.c_str()); bool requiresAppSchemeRegistration = std::any_of( - m_impl->_customSchemeNames.begin(), - m_impl->_customSchemeNames.end(), - [](const std::wstring& schemeName) { - return _wcsicmp(schemeName.c_str(), L"app") == 0; - } - ); + m_impl->_customSchemeNames.begin(), m_impl->_customSchemeNames.end(), + [](const std::wstring& schemeName) { return _wcsicmp(schemeName.c_str(), L"app") == 0; } + ); bool appSchemeRegistrationSupported = false; // Register custom schemes with WebView2 so top-level navigations like app://... are allowed. @@ -104,9 +101,8 @@ void InfiniFrameWindow::AttachWebView() { rawRegistrations.emplace_back(registration.get()); options4->SetCustomSchemeRegistrations( - static_cast(rawRegistrations.size()), - rawRegistrations.data() - ); + static_cast(rawRegistrations.size()), rawRegistrations.data() + ); } } } @@ -114,10 +110,10 @@ void InfiniFrameWindow::AttachWebView() { if (requiresAppSchemeRegistration && !appSchemeRegistrationSupported) { MessageBox( m_impl->_hWnd, - L"This app requires WebView2 custom scheme registration for app://localhost/. Please update WebView2 Runtime to a version that supports ICoreWebView2EnvironmentOptions4.", - L"WebView2 Runtime Too Old", - MB_OK | MB_ICONERROR - ); + L"This app requires WebView2 custom scheme registration for app://localhost/. Please update " + L"WebView2 Runtime to a version that supports ICoreWebView2EnvironmentOptions4.", + L"WebView2 Runtime Too Old", MB_OK | MB_ICONERROR + ); m_impl->_isWebView2Initializing = false; return; } @@ -130,19 +126,13 @@ void InfiniFrameWindow::AttachWebView() { TraceTeardown( L"AttachWebView: temporary user-data path is not writable. Falling back to default path. path=%ls", m_impl->_temporaryFilesPath.c_str() - ); + ); } HRESULT envResult = CreateCoreWebView2EnvironmentWithOptions( - runtimePath, - userDataPath, - options.Get(), - Callback< - ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>( - [this]( - const HRESULT result, - ICoreWebView2Environment* env - ) -> HRESULT { + runtimePath, userDataPath, options.Get(), + Callback( + [this](const HRESULT result, ICoreWebView2Environment* env) -> HRESULT { if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { m_impl->_isWebView2Initializing = false; m_impl->_webviewEnvironment = nullptr; @@ -158,9 +148,7 @@ void InfiniFrameWindow::AttachWebView() { m_impl->_isWebView2Initializing = false; return E_POINTER; } - HRESULT envResult = env->QueryInterface( - &m_impl->_webviewEnvironment - ); + HRESULT envResult = env->QueryInterface(&m_impl->_webviewEnvironment); if (envResult != S_OK) { m_impl->_isWebView2Initializing = false; return envResult; @@ -168,13 +156,8 @@ void InfiniFrameWindow::AttachWebView() { const HRESULT createControllerHr = env->CreateCoreWebView2Controller( m_impl->_hWnd, - Callback< - ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>( - [this]( - const HRESULT result, - ICoreWebView2Controller* controller - ) -> - HRESULT { + Callback( + [this](const HRESULT result, ICoreWebView2Controller* controller) -> HRESULT { if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) { if (controller != nullptr) controller->Close(); @@ -188,9 +171,8 @@ void InfiniFrameWindow::AttachWebView() { if (result != S_OK) { m_impl->_isWebView2Initializing = false; TraceTeardown( - L"CreateController callback failed hr=0x%08X", - static_cast(result) - ); + L"CreateController callback failed hr=0x%08X", static_cast(result) + ); return result; } if (controller == nullptr) { @@ -211,9 +193,8 @@ void InfiniFrameWindow::AttachWebView() { const auto js_wide = Embedded::InfiniFrameJsUtf16(); OutputDebugStringW( - std::format(L"[InfiniFrame] Bridge script length: {} chars\n", js_wide.size()). - c_str() - ); + std::format(L"[InfiniFrame] Bridge script length: {} chars\n", js_wide.size()).c_str() + ); struct NavigateOnce { InfiniFrameWindow* self; @@ -227,14 +208,12 @@ void InfiniFrameWindow::AttachWebView() { else if (!self->m_impl->_startString.empty()) self->m_impl->_webviewWindow->NavigateToString( self->m_impl->_startString.c_str() - ); + ); else { MessageBox( - nullptr, - L"Neither StartUrl nor StartString was specified", - L"Native Initialization Failed", - MB_OK - ); + nullptr, L"Neither StartUrl nor StartString was specified", + L"Native Initialization Failed", MB_OK + ); exit(0); } } @@ -244,9 +223,7 @@ void InfiniFrameWindow::AttachWebView() { wil::com_ptr settings; HRESULT settingsResult = m_impl->_webviewWindow->get_Settings(&settings); if (FAILED(settingsResult) || !settings) { - return FAILED(settingsResult) - ? settingsResult - : E_FAIL; + return FAILED(settingsResult) ? settingsResult : E_FAIL; } settings->put_AreHostObjectsAllowed(TRUE); settings->put_IsScriptEnabled(TRUE); @@ -255,13 +232,8 @@ void InfiniFrameWindow::AttachWebView() { EventRegistrationToken webMessageToken; m_impl->_webviewWindow->add_WebMessageReceived( - Callback< - ICoreWebView2WebMessageReceivedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2WebMessageReceivedEventArgs - * args - ) -> HRESULT { + Callback( + [this](ICoreWebView2*, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT { if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) return S_OK; @@ -269,21 +241,16 @@ void InfiniFrameWindow::AttachWebView() { wil::unique_cotaskmem_string source; args->TryGetWebMessageAsString(&message); args->get_Source(&source); - if ( - (source.get() == nullptr || source.get()[0] == L'\0') - && m_impl->_webviewWindow != nullptr - ) { + if ((source.get() == nullptr || source.get()[0] == L'\0') && + m_impl->_webviewWindow != nullptr) { m_impl->_webviewWindow->get_Source(&source); } - m_impl->_webMessageReceivedCallback( - message.get(), - source.get() - ); + m_impl->_webMessageReceivedCallback(message.get(), source.get()); return S_OK; } - ).Get(), + ).Get(), &webMessageToken - ); + ); m_impl->_webMessageReceivedToken = webMessageToken; m_impl->_hasWebMessageReceivedToken = true; @@ -291,30 +258,21 @@ void InfiniFrameWindow::AttachWebView() { auto webview23 = m_impl->_webviewWindow.try_query(); if (webview23) { webview23->AddWebResourceRequestedFilterWithRequestSourceKinds( - L"*", - COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL - ); - } - else { + ); + } else { m_impl->_webviewWindow->AddWebResourceRequestedFilter( - L"*", - COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL - ); + L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL + ); } m_impl->_webviewWindow->add_WebResourceRequested( - Callback< - ICoreWebView2WebResourceRequestedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2WebResourceRequestedEventArgs - * args - ) { + Callback( + [this](ICoreWebView2*, ICoreWebView2WebResourceRequestedEventArgs* args) { if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) return S_OK; - wil::com_ptr< - ICoreWebView2WebResourceRequest> req; + wil::com_ptr req; if (FAILED(args->get_Request(&req)) || !req) return S_OK; @@ -325,48 +283,37 @@ void InfiniFrameWindow::AttachWebView() { std::wstring requestOrigin; if (SUCCEEDED(req->get_Headers(&requestHeaders)) && requestHeaders) { wil::unique_cotaskmem_string originHeaderValue; - if (SUCCEEDED( - requestHeaders->GetHeader(L"Origin", &originHeaderValue) - ) - && originHeaderValue.get() != nullptr - && originHeaderValue.get()[0] != L'\0') { + if (SUCCEEDED(requestHeaders->GetHeader(L"Origin", &originHeaderValue)) && + originHeaderValue.get() != nullptr && + originHeaderValue.get()[0] != L'\0') { requestOrigin = originHeaderValue.get(); } } - if (uriString.find(L"/_framework/blazor.modules.json") != - std::wstring::npos) { + if (uriString.find(L"/_framework/blazor.modules.json") != std::wstring::npos) { static constexpr BYTE emptyModuleArray[] = {'[', ']'}; wil::com_ptr dataStream; dataStream.attach( SHCreateMemStream(emptyModuleArray, sizeof(emptyModuleArray)) - ); + ); if (!dataStream) return S_OK; std::wstring responseHeaders = L"Content-Type: application/json"; - responseHeaders += - L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; + responseHeaders += L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; if (!requestOrigin.empty()) { - responseHeaders += L"\r\nAccess-Control-Allow-Origin: " + - requestOrigin; - responseHeaders += - L"\r\nAccess-Control-Allow-Credentials: true"; + responseHeaders += L"\r\nAccess-Control-Allow-Origin: " + requestOrigin; + responseHeaders += L"\r\nAccess-Control-Allow-Credentials: true"; responseHeaders += L"\r\nVary: Origin"; - } - else { + } else { responseHeaders += L"\r\nAccess-Control-Allow-Origin: *"; } wil::com_ptr response; m_impl->_webviewEnvironment->CreateWebResourceResponse( - dataStream.get(), - 200, - L"OK", - responseHeaders.c_str(), - &response - ); + dataStream.get(), 200, L"OK", responseHeaders.c_str(), &response + ); args->put_Response(response.get()); return S_OK; } @@ -374,145 +321,73 @@ void InfiniFrameWindow::AttachWebView() { if (colonPos > 0) { std::wstring scheme = uriString.substr(0, colonPos); auto it = std::find( - m_impl - -> - _customSchemeNames - .begin(), - m_impl - -> - _customSchemeNames - .end(), + m_impl->_customSchemeNames.begin(), m_impl->_customSchemeNames.end(), scheme - ); - - if (it != - m_impl-> - _customSchemeNames - .end() && - m_impl-> - _customSchemeCallback - != - nullptr) { + ); + + if (it != m_impl->_customSchemeNames.end() && + m_impl->_customSchemeCallback != nullptr) { int numBytes; AutoString contentType = nullptr; - wil::unique_cotaskmem dotNetResponse( - m_impl - -> - _customSchemeCallback( - const_cast - - (uriString - .c_str()), - &numBytes, - &contentType - ) - ); - auto freeContentType = wil::scope_exit( - [& - contentType - ] { - CoTaskMemFree( - contentType - ); - } - ); + wil::unique_cotaskmem dotNetResponse(m_impl->_customSchemeCallback( + const_cast(uriString.c_str()), &numBytes, &contentType + )); + auto freeContentType = + wil::scope_exit([&contentType] { CoTaskMemFree(contentType); }); - if ( - dotNetResponse - != - nullptr - && - contentType - != - nullptr) { + if (dotNetResponse != nullptr && contentType != nullptr) { std::wstring contentTypeWS = contentType; wil::com_ptr dataStream; - dataStream.attach( - SHCreateMemStream( - reinterpret_cast - - (dotNetResponse - .get()), - numBytes - ) - ); - if (! - dataStream) - return - S_OK; - wil::com_ptr - - response; - std::wstring responseHeaders = L"Content-Type: " + - contentTypeWS; + dataStream.attach(SHCreateMemStream( + reinterpret_cast(dotNetResponse.get()), numBytes + )); + if (!dataStream) + return S_OK; + wil::com_ptr response; + std::wstring responseHeaders = L"Content-Type: " + contentTypeWS; responseHeaders += L"\r\nAccess-Control-Allow-Methods: GET, HEAD, OPTIONS"; responseHeaders += L"\r\nAccess-Control-Allow-Headers: *"; if (!requestOrigin.empty()) { - responseHeaders += L"\r\nAccess-Control-Allow-Origin: " - + requestOrigin; + responseHeaders += + L"\r\nAccess-Control-Allow-Origin: " + requestOrigin; responseHeaders += L"\r\nAccess-Control-Allow-Credentials: true"; responseHeaders += L"\r\nVary: Origin"; + } else { + responseHeaders += L"\r\nAccess-Control-Allow-Origin: *"; } - else { - responseHeaders += - L"\r\nAccess-Control-Allow-Origin: *"; - } - m_impl - -> - _webviewEnvironment - -> - CreateWebResourceResponse( - dataStream - .get(), - 200, - L"OK", - responseHeaders.c_str(), - &response - ); - args-> - put_Response( - response - .get() - ); + m_impl->_webviewEnvironment->CreateWebResourceResponse( + dataStream.get(), 200, L"OK", responseHeaders.c_str(), &response + ); + args->put_Response(response.get()); } } } return S_OK; } - ).Get(), + ).Get(), &webResourceRequestedToken - ); + ); m_impl->_webResourceRequestedTokenForCustomScheme = webResourceRequestedToken; m_impl->_hasWebResourceRequestedToken = true; EventRegistrationToken permissionRequestedToken; m_impl->_webviewWindow->add_PermissionRequested( - Callback< - ICoreWebView2PermissionRequestedEventHandler>( - [this]( - ICoreWebView2*, - ICoreWebView2PermissionRequestedEventArgs - * args - ) -> HRESULT { + Callback( + [this](ICoreWebView2*, ICoreWebView2PermissionRequestedEventArgs* args) -> HRESULT { if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) return S_OK; if (m_impl->_grantBrowserPermissions) - args->put_State( - COREWEBVIEW2_PERMISSION_STATE_ALLOW - ); + args->put_State(COREWEBVIEW2_PERMISSION_STATE_ALLOW); return S_OK; } - ) - .Get(), + ).Get(), &permissionRequestedToken - ); + ); m_impl->_permissionRequestedToken = permissionRequestedToken; m_impl->_hasPermissionRequestedToken = true; @@ -533,11 +408,12 @@ void InfiniFrameWindow::AttachWebView() { [nav, this](HRESULT errorCode, LPCWSTR id) -> HRESULT { OutputDebugStringW( std::format( - L"[InfiniFrame] AddScriptToExecuteOnDocumentCreated callback: hr=0x{:08X} id={}\n", - (unsigned)errorCode, - id ? id : L"(null)" - ).c_str() - ); + L"[InfiniFrame] AddScriptToExecuteOnDocumentCreated callback: " + L"hr=0x{:08X} id={}\n", + (unsigned)errorCode, id ? id : L"(null)" + ) + .c_str() + ); if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) return S_OK; nav->navigate(); @@ -559,15 +435,15 @@ void InfiniFrameWindow::AttachWebView() { m_impl->_isWebView2Initializing = false; return S_OK; } - ).Get() - ); + ).Get() + ); if (FAILED(createControllerHr)) m_impl->_isWebView2Initializing = false; return createControllerHr; } - ).Get() - ); + ).Get() + ); if (envResult != S_OK) { m_impl->_isWebView2Initializing = false; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp index 5f137413d..eb0789bb6 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp @@ -34,24 +34,14 @@ void InfiniFrameWindow::ClearBrowserAutoFill() { if (profile2) { COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds = - (COREWEBVIEW2_BROWSING_DATA_KINDS) - ( - COREWEBVIEW2_BROWSING_DATA_KINDS_GENERAL_AUTOFILL | - COREWEBVIEW2_BROWSING_DATA_KINDS_PASSWORD_AUTOSAVE - ); + (COREWEBVIEW2_BROWSING_DATA_KINDS)(COREWEBVIEW2_BROWSING_DATA_KINDS_GENERAL_AUTOFILL | + COREWEBVIEW2_BROWSING_DATA_KINDS_PASSWORD_AUTOSAVE); profile2->ClearBrowsingData( - dataKinds, - Callback( - [this]( - HRESULT - ) - -> HRESULT { - return S_OK; - } - ) - .Get() - ); + dataKinds, Callback([this](HRESULT) -> HRESULT { + return S_OK; + }).Get() + ); } } } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp index 95cb7ed6e..3f5b7ded4 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp @@ -2,16 +2,11 @@ void InfiniFrameWindow::CloseWebView() { m_impl->_isClosingOrClosed.store(true, std::memory_order_release); - const bool deferEnvironmentRelease = - m_impl->_isWebView2Initializing && m_impl->_webviewController == nullptr; + const bool deferEnvironmentRelease = m_impl->_isWebView2Initializing && m_impl->_webviewController == nullptr; TraceTeardown( - L"CloseWebView begin instance=%p hwnd=%p controller=%p webview=%p env=%p", - this, - m_impl->_hWnd, - m_impl->_webviewController.get(), - m_impl->_webviewWindow.get(), - m_impl->_webviewEnvironment.get() - ); + L"CloseWebView begin instance=%p hwnd=%p controller=%p webview=%p env=%p", this, m_impl->_hWnd, + m_impl->_webviewController.get(), m_impl->_webviewWindow.get(), m_impl->_webviewEnvironment.get() + ); if (m_impl->_webviewController != nullptr) { m_impl->_webviewController->Close(); @@ -37,10 +32,8 @@ void InfiniFrameWindow::CloseWebView() { if (deferEnvironmentRelease) { TraceTeardown( - L"CloseWebView deferring environment release instance=%p env=%p", - this, - m_impl->_webviewEnvironment.get() - ); + L"CloseWebView deferring environment release instance=%p env=%p", this, m_impl->_webviewEnvironment.get() + ); } TraceTeardown(L"CloseWebView end instance=%p", this); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp index 3dda10a56..44e945410 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp @@ -30,18 +30,7 @@ bool InfiniFrameWindow::InstallWebView2() { si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); - bool success = CreateProcess( - nullptr, - command.data(), - nullptr, - nullptr, - FALSE, - 0, - nullptr, - nullptr, - &si, - &pi - ); + bool success = CreateProcess(nullptr, command.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi); if (success) { WaitForSingleObject(pi.hProcess, INFINITE); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h index a3741e81a..c20deba31 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h @@ -38,8 +38,7 @@ HWND ResolveParentWindowHandle(InfiniFrameWindow* parent); HBRUSH GetDarkBrush(); HBRUSH GetLightBrush(); -template -inline void ApplyPendingOwnerWindow(TImpl* impl, const wchar_t* phase) { +template inline void ApplyPendingOwnerWindow(TImpl* impl, const wchar_t* phase) { if (impl == nullptr) return; if (impl->_ownerAssigned) @@ -55,21 +54,15 @@ inline void ApplyPendingOwnerWindow(TImpl* impl, const wchar_t* phase) { return; SetLastError(0); - const LONG_PTR previousOwner = SetWindowLongPtr( - impl->_hWnd, - GWLP_HWNDPARENT, - reinterpret_cast(impl->_pendingOwnerHwnd) - ); + const LONG_PTR previousOwner = + SetWindowLongPtr(impl->_hWnd, GWLP_HWNDPARENT, reinterpret_cast(impl->_pendingOwnerHwnd)); const DWORD lastError = GetLastError(); if (previousOwner == 0 && lastError != 0) { TraceTeardown( - L"ApplyPendingOwnerWindow failed phase=%ls child=%p owner=%p err=%lu", - phase, - impl->_hWnd, - impl->_pendingOwnerHwnd, - lastError - ); + L"ApplyPendingOwnerWindow failed phase=%ls child=%p owner=%p err=%lu", phase, impl->_hWnd, + impl->_pendingOwnerHwnd, lastError + ); return; } @@ -78,14 +71,9 @@ inline void ApplyPendingOwnerWindow(TImpl* impl, const wchar_t* phase) { const DWORD childThreadId = GetWindowThreadProcessId(impl->_hWnd, nullptr); const DWORD ownerThreadId = GetWindowThreadProcessId(impl->_pendingOwnerHwnd, nullptr); TraceTeardown( - L"ApplyPendingOwnerWindow success phase=%ls child=%p owner=%p childTid=%lu ownerTid=%lu prev=%p", - phase, - impl->_hWnd, - impl->_pendingOwnerHwnd, - childThreadId, - ownerThreadId, - reinterpret_cast(previousOwner) - ); + L"ApplyPendingOwnerWindow success phase=%ls child=%p owner=%p childTid=%lu ownerTid=%lu prev=%p", phase, + impl->_hWnd, impl->_pendingOwnerHwnd, childThreadId, ownerThreadId, reinterpret_cast(previousOwner) + ); } #endif // INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_CONTEXT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp index 3aff97b41..1030478ca 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp @@ -1,64 +1,85 @@ #include "Public/Exports/Exports.h" extern "C" { -EXPORTED InteropStatus InfiniFrame_ShowOpenFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, AutoString* filters, const int filterCount, int* resultCount, AutoString** values) { +EXPORTED InteropStatus InfiniFrame_ShowOpenFile( + InfiniFrameWindow* inst, + const AutoString title, + const AutoString defaultPath, + const bool multiSelect, + AutoString* filters, + const int filterCount, + int* resultCount, + AutoString** values +) { ResetOut(resultCount, 0); ResetOut(values, static_cast(nullptr)); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(resultCount, "resultCount")) return; - if (!EnsureOutNotNull(values, "values")) return; - if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); + if (!EnsureOutNotNull(resultCount, "resultCount")) + return; + if (!EnsureOutNotNull(values, "values")) + return; + if (filterCount < 0) + throw std::invalid_argument("Argument 'filterCount' must be >= 0."); *values = window->GetDialog()->ShowOpenFile( - NullToEmpty(title), - NullToEmpty(defaultPath), - multiSelect, - filters, - filterCount, - resultCount + NullToEmpty(title), NullToEmpty(defaultPath), multiSelect, filters, filterCount, resultCount ); }); } -EXPORTED InteropStatus InfiniFrame_ShowOpenFolder(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, const bool multiSelect, int* resultCount, AutoString** values) { +EXPORTED InteropStatus InfiniFrame_ShowOpenFolder( + InfiniFrameWindow* inst, + const AutoString title, + const AutoString defaultPath, + const bool multiSelect, + int* resultCount, + AutoString** values +) { ResetOut(resultCount, 0); ResetOut(values, static_cast(nullptr)); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(resultCount, "resultCount")) return; - if (!EnsureOutNotNull(values, "values")) return; - *values = window->GetDialog()->ShowOpenFolder( - NullToEmpty(title), - NullToEmpty(defaultPath), - multiSelect, - resultCount - ); + if (!EnsureOutNotNull(resultCount, "resultCount")) + return; + if (!EnsureOutNotNull(values, "values")) + return; + *values = + window->GetDialog()->ShowOpenFolder(NullToEmpty(title), NullToEmpty(defaultPath), multiSelect, resultCount); }); } -EXPORTED InteropStatus InfiniFrame_ShowSaveFile(InfiniFrameWindow* inst, const AutoString title, const AutoString defaultPath, AutoString* filters, const int filterCount, const AutoString defaultFileName, AutoString* value) { +EXPORTED InteropStatus InfiniFrame_ShowSaveFile( + InfiniFrameWindow* inst, + const AutoString title, + const AutoString defaultPath, + AutoString* filters, + const int filterCount, + const AutoString defaultFileName, + AutoString* value +) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(value, "value")) return; - if (filterCount < 0) throw std::invalid_argument("Argument 'filterCount' must be >= 0."); + if (!EnsureOutNotNull(value, "value")) + return; + if (filterCount < 0) + throw std::invalid_argument("Argument 'filterCount' must be >= 0."); *value = window->GetDialog()->ShowSaveFile( - NullToEmpty(title), - NullToEmpty(defaultPath), - filters, - filterCount, - NullToEmpty(defaultFileName) + NullToEmpty(title), NullToEmpty(defaultPath), filters, filterCount, NullToEmpty(defaultFileName) ); }); } -EXPORTED InteropStatus InfiniFrame_ShowMessage(InfiniFrameWindow* inst, const AutoString title, const AutoString text, const DialogButtons buttons, const DialogIcon icon, DialogResult* value) { +EXPORTED InteropStatus InfiniFrame_ShowMessage( + InfiniFrameWindow* inst, + const AutoString title, + const AutoString text, + const DialogButtons buttons, + const DialogIcon icon, + DialogResult* value +) { ResetOut(value, DialogResult::Cancel); return RunWindowExportStatus(inst, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(value, "value")) return; - *value = window->GetDialog()->ShowMessage( - NullToEmpty(title), - NullToEmpty(text), - buttons, - icon - ); + if (!EnsureOutNotNull(value, "value")) + return; + *value = window->GetDialog()->ShowMessage(NullToEmpty(title), NullToEmpty(text), buttons, icon); }); } } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp index e3940594f..669c81bf5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp @@ -3,14 +3,16 @@ extern "C" { EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(scheme, "scheme")) return; + if (!EnsureNotNull(scheme, "scheme")) + return; window->AddCustomSchemeName(scheme); }); } EXPORTED InteropStatus InfiniFrame_GetAllMonitors(InfiniFrameWindow* instance, const GetAllMonitorsCallback callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (callback == nullptr) throw std::invalid_argument("Argument 'callback' is null."); + if (callback == nullptr) + throw std::invalid_argument("Argument 'callback' is null."); window->GetAllMonitors(callback); }); } @@ -41,7 +43,8 @@ EXPORTED InteropStatus InfiniFrame_SetResizedCallback(InfiniFrameWindow* instanc EXPORTED InteropStatus InfiniFrame_Invoke(InfiniFrameWindow* instance, const ACTION callback) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (callback == nullptr) throw std::invalid_argument("Argument 'callback' is null."); + if (callback == nullptr) + throw std::invalid_argument("Argument 'callback' is null."); window->Invoke(callback); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp index 2437932ba..b05352241 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp @@ -4,8 +4,10 @@ extern "C" { EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { ResetOut(value, static_cast(nullptr)); return RunExportStatus([&] { - if (!EnsureOutNotNull(value, "value")) return; - if (initParams == nullptr) throw std::invalid_argument("Argument 'initParams' is null."); + if (!EnsureOutNotNull(value, "value")) + return; + if (initParams == nullptr) + throw std::invalid_argument("Argument 'initParams' is null."); if (initParams->Size != static_cast(sizeof(InfiniFrameInitParams))) { throw std::invalid_argument("InfiniFrameInitParams.Size does not match native struct size."); } @@ -16,7 +18,8 @@ EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, Infin EXPORTED InteropStatus InfiniFrame_dtor(InfiniFrameWindow* instance) { return RunExportStatus([&] { - if (!EnsureNotNull(instance, "instance")) return; + if (!EnsureNotNull(instance, "instance")) + return; std::unique_ptr guard{instance}; }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp index 8fad4dac0..584242e46 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp @@ -3,7 +3,8 @@ extern "C" { EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { return RunExportStatus([&] { - if (!EnsureNotNull(value, "value")) return; + if (!EnsureNotNull(value, "value")) + return; #ifdef _WIN32 delete[] value; #elif __linux__ @@ -16,8 +17,10 @@ EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { EXPORTED InteropStatus InfiniFrame_FreeStringArray(AutoString* values, const int count) { return RunExportStatus([&] { - if (!EnsureNotNull(values, "values")) return; - if (count < 0) throw std::invalid_argument("Argument 'count' must be >= 0."); + if (!EnsureNotNull(values, "values")) + return; + if (count < 0) + throw std::invalid_argument("Argument 'count' must be >= 0."); for (int i = 0; i < count; ++i) { if (values[i] != nullptr) { InfiniFrame_FreeString(values[i]); @@ -36,7 +39,8 @@ EXPORTED InteropStatus InfiniFrame_FreeStringArray(AutoString* values, const int EXPORTED InteropStatus InfiniFrame_GetLastErrorMessage(AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunExportStatus([&] { - if (!EnsureOutNotNull(value, "value")) return; + if (!EnsureOutNotNull(value, "value")) + return; *value = GetLastErrorMessageCopy(); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp index e15f54bf1..8207deb29 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp @@ -4,7 +4,8 @@ extern "C" { #ifdef _WIN32 EXPORTED InteropStatus InfiniFrame_register_win32(const HINSTANCE hInstance) { return RunExportStatus([&] { - if (hInstance == nullptr) throw std::invalid_argument("Argument 'hInstance' is null."); + if (hInstance == nullptr) + throw std::invalid_argument("Argument 'hInstance' is null."); InfiniFrameWindow::Register(hInstance); }); } @@ -12,14 +13,17 @@ EXPORTED InteropStatus InfiniFrame_register_win32(const HINSTANCE hInstance) { EXPORTED InteropStatus InfiniFrame_getHwnd_win32(InfiniFrameWindow* instance, HWND* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(value, "value")) return; + if (!EnsureOutNotNull(value, "value")) + return; *value = window->getHwnd(); }); } -EXPORTED InteropStatus InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindow*, const AutoString webView2RuntimePath) { +EXPORTED InteropStatus +InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindow*, const AutoString webView2RuntimePath) { return RunExportStatus([&] { - if (!EnsureNotNull(webView2RuntimePath, "webView2RuntimePath")) return; + if (!EnsureNotNull(webView2RuntimePath, "webView2RuntimePath")) + return; InfiniFrameWindow::SetWebView2RuntimePath(webView2RuntimePath); }); } @@ -27,7 +31,8 @@ EXPORTED InteropStatus InfiniFrame_setWebView2RuntimePath_win32(InfiniFrameWindo EXPORTED InteropStatus InfiniFrame_GetNotificationsEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetNotificationsEnabled(enabled); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp index 6b364aa09..4e9b5a0fb 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp @@ -37,98 +37,97 @@ inline AutoString duplicateString(const AutoStringConst str) { #endif extern "C" { - EXPORTED InteropStatus InfiniFrameNativeTests_NativeParametersReturnAsIs( - const InfiniFrameInitParams* params, - InfiniFrameInitParams** new_params - ) { - if (new_params != nullptr) { - *new_params = nullptr; +EXPORTED InteropStatus InfiniFrameNativeTests_NativeParametersReturnAsIs( + const InfiniFrameInitParams* params, InfiniFrameInitParams** new_params +) { + if (new_params != nullptr) { + *new_params = nullptr; + } + + return RunExportStatus([&] { + if (!EnsureNotNull(params, "params") || + !EnsureNotNull(new_params, "new_params", ::InteropStatus::OutParameterSetToInvalidNull)) { + return; } - return RunExportStatus([&] { - if (!EnsureNotNull(params, "params") - || !EnsureNotNull(new_params, "new_params", ::InteropStatus::OutParameterSetToInvalidNull)) { - return; - } - - *new_params = new InfiniFrameInitParams(); - - (*new_params)->StartString = duplicateString(params->StartString); - (*new_params)->StartUrl = duplicateString(params->StartUrl); - (*new_params)->Title = duplicateString(params->Title); - (*new_params)->WindowIconFile = duplicateString(params->WindowIconFile); - (*new_params)->TemporaryFilesPath = duplicateString(params->TemporaryFilesPath); - (*new_params)->UserAgent = duplicateString(params->UserAgent); - (*new_params)->BrowserControlInitParameters = duplicateString(params->BrowserControlInitParameters); - (*new_params)->NotificationRegistrationId = duplicateString(params->NotificationRegistrationId); - - (*new_params)->ParentInstance = params->ParentInstance; - (*new_params)->ClosingHandler = params->ClosingHandler; - (*new_params)->ClosedHandler = params->ClosedHandler; - (*new_params)->FocusInHandler = params->FocusInHandler; - (*new_params)->FocusOutHandler = params->FocusOutHandler; - (*new_params)->ResizedHandler = params->ResizedHandler; - (*new_params)->MaximizedHandler = params->MaximizedHandler; - (*new_params)->RestoredHandler = params->RestoredHandler; - (*new_params)->MinimizedHandler = params->MinimizedHandler; - (*new_params)->MovedHandler = params->MovedHandler; - (*new_params)->WebMessageReceivedHandler = params->WebMessageReceivedHandler; - (*new_params)->CustomSchemeHandler = params->CustomSchemeHandler; - memcpy((*new_params)->CustomSchemeNames, params->CustomSchemeNames, sizeof(params->CustomSchemeNames)); - - (*new_params)->Left = params->Left; - (*new_params)->Top = params->Top; - (*new_params)->Width = params->Width; - (*new_params)->Height = params->Height; - (*new_params)->Zoom = params->Zoom; - (*new_params)->MinWidth = params->MinWidth; - (*new_params)->MinHeight = params->MinHeight; - (*new_params)->MaxWidth = params->MaxWidth; - (*new_params)->MaxHeight = params->MaxHeight; - (*new_params)->CenterOnInitialize = params->CenterOnInitialize; - (*new_params)->Chromeless = params->Chromeless; - (*new_params)->Transparent = params->Transparent; - (*new_params)->ContextMenuEnabled = params->ContextMenuEnabled; - (*new_params)->ZoomEnabled = params->ZoomEnabled; - (*new_params)->DevToolsEnabled = params->DevToolsEnabled; - (*new_params)->FullScreen = params->FullScreen; - (*new_params)->Maximized = params->Maximized; - (*new_params)->Minimized = params->Minimized; - (*new_params)->Resizable = params->Resizable; - (*new_params)->Topmost = params->Topmost; - (*new_params)->UseOsDefaultLocation = params->UseOsDefaultLocation; - (*new_params)->UseOsDefaultSize = params->UseOsDefaultSize; - (*new_params)->GrantBrowserPermissions = params->GrantBrowserPermissions; - (*new_params)->MediaAutoplayEnabled = params->MediaAutoplayEnabled; - (*new_params)->FileSystemAccessEnabled = params->FileSystemAccessEnabled; - (*new_params)->WebSecurityEnabled = params->WebSecurityEnabled; - (*new_params)->JavascriptClipboardAccessEnabled = params->JavascriptClipboardAccessEnabled; - (*new_params)->MediaStreamEnabled = params->MediaStreamEnabled; - (*new_params)->SmoothScrollingEnabled = params->SmoothScrollingEnabled; - (*new_params)->IgnoreCertificateErrorsEnabled = params->IgnoreCertificateErrorsEnabled; - (*new_params)->NotificationsEnabled = params->NotificationsEnabled; - (*new_params)->Size = params->Size; - }); - } + *new_params = new InfiniFrameInitParams(); + + (*new_params)->StartString = duplicateString(params->StartString); + (*new_params)->StartUrl = duplicateString(params->StartUrl); + (*new_params)->Title = duplicateString(params->Title); + (*new_params)->WindowIconFile = duplicateString(params->WindowIconFile); + (*new_params)->TemporaryFilesPath = duplicateString(params->TemporaryFilesPath); + (*new_params)->UserAgent = duplicateString(params->UserAgent); + (*new_params)->BrowserControlInitParameters = duplicateString(params->BrowserControlInitParameters); + (*new_params)->NotificationRegistrationId = duplicateString(params->NotificationRegistrationId); + + (*new_params)->ParentInstance = params->ParentInstance; + (*new_params)->ClosingHandler = params->ClosingHandler; + (*new_params)->ClosedHandler = params->ClosedHandler; + (*new_params)->FocusInHandler = params->FocusInHandler; + (*new_params)->FocusOutHandler = params->FocusOutHandler; + (*new_params)->ResizedHandler = params->ResizedHandler; + (*new_params)->MaximizedHandler = params->MaximizedHandler; + (*new_params)->RestoredHandler = params->RestoredHandler; + (*new_params)->MinimizedHandler = params->MinimizedHandler; + (*new_params)->MovedHandler = params->MovedHandler; + (*new_params)->WebMessageReceivedHandler = params->WebMessageReceivedHandler; + (*new_params)->CustomSchemeHandler = params->CustomSchemeHandler; + memcpy((*new_params)->CustomSchemeNames, params->CustomSchemeNames, sizeof(params->CustomSchemeNames)); + + (*new_params)->Left = params->Left; + (*new_params)->Top = params->Top; + (*new_params)->Width = params->Width; + (*new_params)->Height = params->Height; + (*new_params)->Zoom = params->Zoom; + (*new_params)->MinWidth = params->MinWidth; + (*new_params)->MinHeight = params->MinHeight; + (*new_params)->MaxWidth = params->MaxWidth; + (*new_params)->MaxHeight = params->MaxHeight; + (*new_params)->CenterOnInitialize = params->CenterOnInitialize; + (*new_params)->Chromeless = params->Chromeless; + (*new_params)->Transparent = params->Transparent; + (*new_params)->ContextMenuEnabled = params->ContextMenuEnabled; + (*new_params)->ZoomEnabled = params->ZoomEnabled; + (*new_params)->DevToolsEnabled = params->DevToolsEnabled; + (*new_params)->FullScreen = params->FullScreen; + (*new_params)->Maximized = params->Maximized; + (*new_params)->Minimized = params->Minimized; + (*new_params)->Resizable = params->Resizable; + (*new_params)->Topmost = params->Topmost; + (*new_params)->UseOsDefaultLocation = params->UseOsDefaultLocation; + (*new_params)->UseOsDefaultSize = params->UseOsDefaultSize; + (*new_params)->GrantBrowserPermissions = params->GrantBrowserPermissions; + (*new_params)->MediaAutoplayEnabled = params->MediaAutoplayEnabled; + (*new_params)->FileSystemAccessEnabled = params->FileSystemAccessEnabled; + (*new_params)->WebSecurityEnabled = params->WebSecurityEnabled; + (*new_params)->JavascriptClipboardAccessEnabled = params->JavascriptClipboardAccessEnabled; + (*new_params)->MediaStreamEnabled = params->MediaStreamEnabled; + (*new_params)->SmoothScrollingEnabled = params->SmoothScrollingEnabled; + (*new_params)->IgnoreCertificateErrorsEnabled = params->IgnoreCertificateErrorsEnabled; + (*new_params)->NotificationsEnabled = params->NotificationsEnabled; + (*new_params)->Size = params->Size; + }); +} - EXPORTED InteropStatus InfiniFrameNativeTests_FreeInitParams(InfiniFrameInitParams* params) { - return RunExportStatus([&] { - if (!EnsureNotNull(params, "params")) { - return; - } - - delete[] params->StartString; - delete[] params->StartUrl; - delete[] params->Title; - delete[] params->WindowIconFile; - delete[] params->TemporaryFilesPath; - delete[] params->UserAgent; - delete[] params->BrowserControlInitParameters; - delete[] params->NotificationRegistrationId; - - delete params; - }); - } +EXPORTED InteropStatus InfiniFrameNativeTests_FreeInitParams(InfiniFrameInitParams* params) { + return RunExportStatus([&] { + if (!EnsureNotNull(params, "params")) { + return; + } + + delete[] params->StartString; + delete[] params->StartUrl; + delete[] params->Title; + delete[] params->WindowIconFile; + delete[] params->TemporaryFilesPath; + delete[] params->UserAgent; + delete[] params->BrowserControlInitParameters; + delete[] params->NotificationRegistrationId; + + delete params; + }); +} } #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp index 30a49b1a8..9f9f0f6de 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp @@ -11,14 +11,16 @@ EXPORTED InteropStatus InfiniFrame_ClearBrowserAutoFill(InfiniFrameWindow* insta EXPORTED InteropStatus InfiniFrame_NavigateToString(InfiniFrameWindow* instance, const AutoString content) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(content, "content")) return; + if (!EnsureNotNull(content, "content")) + return; window->NavigateToString(content); }); } EXPORTED InteropStatus InfiniFrame_NavigateToUrl(InfiniFrameWindow* instance, const AutoString url) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureNotNull(url, "url")) return; + if (!EnsureNotNull(url, "url")) + return; window->NavigateToUrl(url); }); } @@ -88,9 +90,7 @@ EXPORTED InteropStatus InfiniFrame_SetSize(InfiniFrameWindow* instance, const in } EXPORTED InteropStatus InfiniFrame_SetTitle(InfiniFrameWindow* instance, const AutoString title) { - return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - window->SetTitle(NullToEmpty(title)); - }); + return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetTitle(NullToEmpty(title)); }); } EXPORTED InteropStatus InfiniFrame_SetTopmost(InfiniFrameWindow* instance, const bool topmost) { @@ -101,12 +101,10 @@ EXPORTED InteropStatus InfiniFrame_SetZoom(InfiniFrameWindow* instance, const in return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { window->SetZoom(zoom); }); } -EXPORTED InteropStatus InfiniFrame_ShowNotification(InfiniFrameWindow* instance, const AutoString title, const AutoString body) { +EXPORTED InteropStatus +InfiniFrame_ShowNotification(InfiniFrameWindow* instance, const AutoString title, const AutoString body) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - window->ShowNotification( - NullToEmpty(title), - NullToEmpty(body) - ); + window->ShowNotification(NullToEmpty(title), NullToEmpty(body)); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp index 5ef584256..6003e3ac0 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp @@ -4,7 +4,8 @@ extern "C" { EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetTransparentEnabled(enabled); }); } @@ -12,7 +13,8 @@ EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* inst EXPORTED InteropStatus InfiniFrame_GetContextMenuEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetContextMenuEnabled(enabled); }); } @@ -20,7 +22,8 @@ EXPORTED InteropStatus InfiniFrame_GetContextMenuEnabled(InfiniFrameWindow* inst EXPORTED InteropStatus InfiniFrame_GetZoomEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetZoomEnabled(enabled); }); } @@ -28,7 +31,8 @@ EXPORTED InteropStatus InfiniFrame_GetZoomEnabled(InfiniFrameWindow* instance, b EXPORTED InteropStatus InfiniFrame_GetDevToolsEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetDevToolsEnabled(enabled); }); } @@ -36,7 +40,8 @@ EXPORTED InteropStatus InfiniFrame_GetDevToolsEnabled(InfiniFrameWindow* instanc EXPORTED InteropStatus InfiniFrame_GetFullScreen(InfiniFrameWindow* instance, bool* fullScreen) { ResetOut(fullScreen, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(fullScreen, "fullScreen")) return; + if (!EnsureOutNotNull(fullScreen, "fullScreen")) + return; window->GetFullScreen(fullScreen); }); } @@ -44,7 +49,8 @@ EXPORTED InteropStatus InfiniFrame_GetFullScreen(InfiniFrameWindow* instance, bo EXPORTED InteropStatus InfiniFrame_GetGrantBrowserPermissions(InfiniFrameWindow* instance, bool* grant) { ResetOut(grant, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(grant, "grant")) return; + if (!EnsureOutNotNull(grant, "grant")) + return; window->GetGrantBrowserPermissions(grant); }); } @@ -52,7 +58,8 @@ EXPORTED InteropStatus InfiniFrame_GetGrantBrowserPermissions(InfiniFrameWindow* EXPORTED InteropStatus InfiniFrame_GetUserAgent(InfiniFrameWindow* instance, AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(value, "value")) return; + if (!EnsureOutNotNull(value, "value")) + return; *value = window->GetUserAgent(); }); } @@ -60,7 +67,8 @@ EXPORTED InteropStatus InfiniFrame_GetUserAgent(InfiniFrameWindow* instance, Aut EXPORTED InteropStatus InfiniFrame_GetMediaAutoplayEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetMediaAutoplayEnabled(enabled); }); } @@ -68,7 +76,8 @@ EXPORTED InteropStatus InfiniFrame_GetMediaAutoplayEnabled(InfiniFrameWindow* in EXPORTED InteropStatus InfiniFrame_GetFileSystemAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetFileSystemAccessEnabled(enabled); }); } @@ -76,7 +85,8 @@ EXPORTED InteropStatus InfiniFrame_GetFileSystemAccessEnabled(InfiniFrameWindow* EXPORTED InteropStatus InfiniFrame_GetWebSecurityEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetWebSecurityEnabled(enabled); }); } @@ -84,7 +94,8 @@ EXPORTED InteropStatus InfiniFrame_GetWebSecurityEnabled(InfiniFrameWindow* inst EXPORTED InteropStatus InfiniFrame_GetJavascriptClipboardAccessEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetJavascriptClipboardAccessEnabled(enabled); }); } @@ -92,7 +103,8 @@ EXPORTED InteropStatus InfiniFrame_GetJavascriptClipboardAccessEnabled(InfiniFra EXPORTED InteropStatus InfiniFrame_GetMediaStreamEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetMediaStreamEnabled(enabled); }); } @@ -100,7 +112,8 @@ EXPORTED InteropStatus InfiniFrame_GetMediaStreamEnabled(InfiniFrameWindow* inst EXPORTED InteropStatus InfiniFrame_GetSmoothScrollingEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetSmoothScrollingEnabled(enabled); }); } @@ -108,7 +121,8 @@ EXPORTED InteropStatus InfiniFrame_GetSmoothScrollingEnabled(InfiniFrameWindow* EXPORTED InteropStatus InfiniFrame_GetMaximized(InfiniFrameWindow* instance, bool* isMaximized) { ResetOut(isMaximized, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(isMaximized, "isMaximized")) return; + if (!EnsureOutNotNull(isMaximized, "isMaximized")) + return; window->GetMaximized(isMaximized); }); } @@ -116,7 +130,8 @@ EXPORTED InteropStatus InfiniFrame_GetMaximized(InfiniFrameWindow* instance, boo EXPORTED InteropStatus InfiniFrame_GetMinimized(InfiniFrameWindow* instance, bool* isMinimized) { ResetOut(isMinimized, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(isMinimized, "isMinimized")) return; + if (!EnsureOutNotNull(isMinimized, "isMinimized")) + return; window->GetMinimized(isMinimized); }); } @@ -124,7 +139,8 @@ EXPORTED InteropStatus InfiniFrame_GetMinimized(InfiniFrameWindow* instance, boo EXPORTED InteropStatus InfiniFrame_GetIgnoreCertificateErrorsEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(enabled, "enabled")) return; + if (!EnsureOutNotNull(enabled, "enabled")) + return; window->GetIgnoreCertificateErrorsEnabled(enabled); }); } @@ -132,7 +148,8 @@ EXPORTED InteropStatus InfiniFrame_GetIgnoreCertificateErrorsEnabled(InfiniFrame EXPORTED InteropStatus InfiniFrame_GetPosition(InfiniFrameWindow* instance, int* x, int* y) { ResetOut2(x, y, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(x, "x") || !EnsureOutNotNull(y, "y")) return; + if (!EnsureOutNotNull(x, "x") || !EnsureOutNotNull(y, "y")) + return; window->GetPosition(x, y); }); } @@ -140,7 +157,8 @@ EXPORTED InteropStatus InfiniFrame_GetPosition(InfiniFrameWindow* instance, int* EXPORTED InteropStatus InfiniFrame_GetResizable(InfiniFrameWindow* instance, bool* resizable) { ResetOut(resizable, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(resizable, "resizable")) return; + if (!EnsureOutNotNull(resizable, "resizable")) + return; window->GetResizable(resizable); }); } @@ -148,7 +166,8 @@ EXPORTED InteropStatus InfiniFrame_GetResizable(InfiniFrameWindow* instance, boo EXPORTED InteropStatus InfiniFrame_GetScreenDpi(InfiniFrameWindow* instance, unsigned int* value) { ResetOut(value, static_cast(0)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(value, "value")) return; + if (!EnsureOutNotNull(value, "value")) + return; *value = window->GetScreenDpi(); }); } @@ -156,7 +175,8 @@ EXPORTED InteropStatus InfiniFrame_GetScreenDpi(InfiniFrameWindow* instance, uns EXPORTED InteropStatus InfiniFrame_GetSize(InfiniFrameWindow* instance, int* width, int* height) { ResetOut2(width, height, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) return; + if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) + return; window->GetSize(width, height); }); } @@ -164,7 +184,8 @@ EXPORTED InteropStatus InfiniFrame_GetSize(InfiniFrameWindow* instance, int* wid EXPORTED InteropStatus InfiniFrame_GetMaxSize(InfiniFrameWindow* instance, int* width, int* height) { ResetOut2(width, height, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) return; + if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) + return; window->GetMaxSize(width, height); }); } @@ -172,7 +193,8 @@ EXPORTED InteropStatus InfiniFrame_GetMaxSize(InfiniFrameWindow* instance, int* EXPORTED InteropStatus InfiniFrame_GetMinSize(InfiniFrameWindow* instance, int* width, int* height) { ResetOut2(width, height, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) return; + if (!EnsureOutNotNull(width, "width") || !EnsureOutNotNull(height, "height")) + return; window->GetMinSize(width, height); }); } @@ -180,7 +202,8 @@ EXPORTED InteropStatus InfiniFrame_GetMinSize(InfiniFrameWindow* instance, int* EXPORTED InteropStatus InfiniFrame_GetTitle(InfiniFrameWindow* instance, AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(value, "value")) return; + if (!EnsureOutNotNull(value, "value")) + return; *value = window->GetTitle(); }); } @@ -188,7 +211,8 @@ EXPORTED InteropStatus InfiniFrame_GetTitle(InfiniFrameWindow* instance, AutoStr EXPORTED InteropStatus InfiniFrame_GetTopmost(InfiniFrameWindow* instance, bool* topmost) { ResetOut(topmost, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(topmost, "topmost")) return; + if (!EnsureOutNotNull(topmost, "topmost")) + return; window->GetTopmost(topmost); }); } @@ -196,7 +220,8 @@ EXPORTED InteropStatus InfiniFrame_GetTopmost(InfiniFrameWindow* instance, bool* EXPORTED InteropStatus InfiniFrame_GetZoom(InfiniFrameWindow* instance, int* zoom) { ResetOut(zoom, 0); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(zoom, "zoom")) return; + if (!EnsureOutNotNull(zoom, "zoom")) + return; window->GetZoom(zoom); }); } @@ -204,7 +229,8 @@ EXPORTED InteropStatus InfiniFrame_GetZoom(InfiniFrameWindow* instance, int* zoo EXPORTED InteropStatus InfiniFrame_GetFocused(InfiniFrameWindow* instance, bool* isFocused) { ResetOut(isFocused, false); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(isFocused, "isFocused")) return; + if (!EnsureOutNotNull(isFocused, "isFocused")) + return; window->GetFocused(isFocused); }); } @@ -212,7 +238,8 @@ EXPORTED InteropStatus InfiniFrame_GetFocused(InfiniFrameWindow* instance, bool* EXPORTED InteropStatus InfiniFrame_GetIconFileName(InfiniFrameWindow* instance, AutoString* value) { ResetOut(value, static_cast(nullptr)); return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { - if (!EnsureOutNotNull(value, "value")) return; + if (!EnsureOutNotNull(value, "value")) + return; *value = window->GetIconFileName(); }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h index ac5592110..98790ba46 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h @@ -25,8 +25,7 @@ using infiniframe::exports::RunReturnExport; using infiniframe::exports::RunWindowExportStatus; using infiniframe::exports::RunWindowReturnExport; -template -inline bool EnsureOutNotNull(T* value, const char* argumentName) noexcept { +template inline bool EnsureOutNotNull(T* value, const char* argumentName) noexcept { return infiniframe::exports::EnsureNotNull(value, argumentName, InteropStatus::OutParameterSetToInvalidNull); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h index 880fce5dd..7c0f1967e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h @@ -20,26 +20,26 @@ class InfiniFrameWindow; // forward declaration * @brief Dialog handler for file/folder operations and message boxes */ class InfiniFrameDialog { - public: +public: #ifdef _WIN32 - /** + /** * @brief Construct dialog handler with parent window (Windows) * @param window Parent InfiniFrame window */ - InfiniFrameDialog(InfiniFrameWindow* window); + InfiniFrameDialog(InfiniFrameWindow* window); #else - /** + /** * @brief Construct dialog handler (Linux/macOS) */ - InfiniFrameDialog(); + InfiniFrameDialog(); #endif - /** + /** * @brief Destroy dialog handler */ - ~InfiniFrameDialog(); + ~InfiniFrameDialog(); - /** + /** * @brief Show open file dialog * @param title Dialog title * @param defaultPath Default path @@ -49,16 +49,16 @@ class InfiniFrameDialog { * @param resultCount Output: number of selected files * @return Array of selected file paths */ - AutoString* ShowOpenFile( - AutoString title, - AutoString defaultPath, - bool multiSelect, - AutoString* filters, - int filterCount, - int* resultCount - ); + AutoString* ShowOpenFile( + AutoString title, + AutoString defaultPath, + bool multiSelect, + AutoString* filters, + int filterCount, + int* resultCount + ); - /** + /** * @brief Show open folder dialog * @param title Dialog title * @param defaultPath Default path @@ -66,9 +66,9 @@ class InfiniFrameDialog { * @param resultCount Output: number of selected folders * @return Array of selected folder paths */ - AutoString* ShowOpenFolder(AutoString title, AutoString defaultPath, bool multiSelect, int* resultCount); + AutoString* ShowOpenFolder(AutoString title, AutoString defaultPath, bool multiSelect, int* resultCount); - /** + /** * @brief Show save file dialog * @param title Dialog title * @param defaultPath Default path @@ -77,15 +77,15 @@ class InfiniFrameDialog { * @param defaultFileName Default file name * @return Selected file path */ - AutoString ShowSaveFile( - AutoString title, - AutoString defaultPath, - AutoString* filters, - int filterCount, - AutoString defaultFileName = nullptr - ); + AutoString ShowSaveFile( + AutoString title, + AutoString defaultPath, + AutoString* filters, + int filterCount, + AutoString defaultFileName = nullptr + ); - /** + /** * @brief Show message dialog * @param title Dialog title * @param text Message text @@ -93,16 +93,16 @@ class InfiniFrameDialog { * @param icon Icon type * @return User's response */ - DialogResult ShowMessage(AutoString title, AutoString text, DialogButtons buttons, DialogIcon icon); + DialogResult ShowMessage(AutoString title, AutoString text, DialogButtons buttons, DialogIcon icon); - protected: +protected: #ifdef __APPLE__ - NSImage* _errorIcon; - NSImage* _infoIcon; - NSImage* _questionIcon; - NSImage* _warningIcon; + NSImage* _errorIcon; + NSImage* _infoIcon; + NSImage* _questionIcon; + NSImage* _warningIcon; #elif _WIN32 - InfiniFrameWindow* _window; + InfiniFrameWindow* _window; #endif }; diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h index eca5cca3d..3e94ede0c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h @@ -47,555 +47,555 @@ struct InfiniFrameInitParams; * Supports Windows (Win32 + WebView2), Linux (GTK3 + WebKit2GTK), macOS (Cocoa + WKWebView) */ class InfiniFrameWindow { - public: - /** +public: + /** * @brief Construct new InfiniFrame window * @param initParams Initialization parameters */ - explicit InfiniFrameWindow(InfiniFrameInitParams* initParams); + explicit InfiniFrameWindow(InfiniFrameInitParams* initParams); - /** + /** * @brief Destroy InfiniFrame window */ - ~InfiniFrameWindow(); + ~InfiniFrameWindow(); - /** + /** * @brief Get dialog handler * @return Pointer to InfiniFrameDialog */ - [[nodiscard]] InfiniFrameDialog* GetDialog() const; + [[nodiscard]] InfiniFrameDialog* GetDialog() const; - // ----------------------------------------------------------------------------------------------------------------- - // Window Operations - // ----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- + // Window Operations + // ----------------------------------------------------------------------------------------------------------------- - /** @brief Center the window on the current screen */ - void Center(); + /** @brief Center the window on the current screen */ + void Center(); - /** @brief Clear all browser autofill data (passwords, forms) */ - void ClearBrowserAutoFill(); + /** @brief Clear all browser autofill data (passwords, forms) */ + void ClearBrowserAutoFill(); - /** @brief Close the window and terminate the message loop */ - void Close(); + /** @brief Close the window and terminate the message loop */ + void Close(); - // ----------------------------------------------------------------------------------------------------------------- - // Get Properties - // ----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- + // Get Properties + // ----------------------------------------------------------------------------------------------------------------- - /** + /** * @brief Get whether transparent background is enabled * @param enabled Output: true if transparent background is active */ - void GetTransparentEnabled(bool* enabled) const; + void GetTransparentEnabled(bool* enabled) const; - /** + /** * @brief Get whether the browser context menu is enabled * @param enabled Output: true if context menu is shown on right-click */ - void GetContextMenuEnabled(bool* enabled) const; + void GetContextMenuEnabled(bool* enabled) const; - /** + /** * @brief Get whether user-controlled zoom is enabled * @param enabled Output: true if the user can zoom via keyboard/mouse */ - void GetZoomEnabled(bool* enabled) const; + void GetZoomEnabled(bool* enabled) const; - /** + /** * @brief Get whether the browser DevTools panel is enabled * @param enabled Output: true if DevTools can be opened */ - void GetDevToolsEnabled(bool* enabled) const; + void GetDevToolsEnabled(bool* enabled) const; - /** + /** * @brief Get whether the window is in fullscreen mode * @param fullScreen Output: true if the window occupies the full screen */ - void GetFullScreen(bool* fullScreen) const; + void GetFullScreen(bool* fullScreen) const; - /** + /** * @brief Get whether browser permission requests are auto-granted * @param grant Output: true if permissions (camera, microphone, etc.) are granted without prompting */ - void GetGrantBrowserPermissions(bool* grant) const; + void GetGrantBrowserPermissions(bool* grant) const; - /** + /** * @brief Get the custom user-agent string * @return UTF-8 user-agent string; caller must free with InfiniFrame_FreeString */ - [[nodiscard]] AutoString GetUserAgent() const; + [[nodiscard]] AutoString GetUserAgent() const; - /** + /** * @brief Get whether media autoplay is enabled * @param enabled Output: true if audio/video may autoplay without user interaction */ - void GetMediaAutoplayEnabled(bool* enabled) const; + void GetMediaAutoplayEnabled(bool* enabled) const; - /** + /** * @brief Get whether the File System Access API is enabled * @param enabled Output: true if web content may access the local file system */ - void GetFileSystemAccessEnabled(bool* enabled) const; + void GetFileSystemAccessEnabled(bool* enabled) const; - /** + /** * @brief Get whether web security (same-origin / CORS) is enabled * @param enabled Output: true if standard web security restrictions are enforced */ - void GetWebSecurityEnabled(bool* enabled) const; + void GetWebSecurityEnabled(bool* enabled) const; - /** + /** * @brief Get whether JavaScript clipboard read/write access is enabled * @param enabled Output: true if the Clipboard API is accessible from scripts */ - void GetJavascriptClipboardAccessEnabled(bool* enabled) const; + void GetJavascriptClipboardAccessEnabled(bool* enabled) const; - /** + /** * @brief Get whether the MediaStream API is enabled * @param enabled Output: true if camera/microphone streaming is permitted */ - void GetMediaStreamEnabled(bool* enabled) const; + void GetMediaStreamEnabled(bool* enabled) const; - /** + /** * @brief Get whether smooth scrolling is enabled * @param enabled Output: true if CSS smooth-scroll behaviour is active */ - void GetSmoothScrollingEnabled(bool* enabled) const; + void GetSmoothScrollingEnabled(bool* enabled) const; - /** + /** * @brief Get the window icon file path * @return UTF-8 path to the icon file; caller must free with InfiniFrame_FreeString */ - [[nodiscard]] AutoString GetIconFileName() const; + [[nodiscard]] AutoString GetIconFileName() const; - /** + /** * @brief Get whether the window is maximized * @param isMaximized Output: true if the window is currently maximized */ - void GetMaximized(bool* isMaximized) const; + void GetMaximized(bool* isMaximized) const; - /** + /** * @brief Get whether the window is minimized * @param isMinimized Output: true if the window is currently minimized */ - void GetMinimized(bool* isMinimized) const; + void GetMinimized(bool* isMinimized) const; - /** + /** * @brief Get the window position in screen coordinates * @param x Output: left edge position in pixels * @param y Output: top edge position in pixels */ - void GetPosition(int* x, int* y) const; + void GetPosition(int* x, int* y) const; - /** + /** * @brief Get whether the window can be resized by the user * @param resizable Output: true if the window has a resizable border */ - void GetResizable(bool* resizable) const; + void GetResizable(bool* resizable) const; - /** + /** * @brief Get the DPI of the screen the window is on * @return DPI value (e.g. 96 for 100%, 192 for 200%) */ - [[nodiscard]] unsigned int GetScreenDpi() const; + [[nodiscard]] unsigned int GetScreenDpi() const; - /** + /** * @brief Get the current window size * @param width Output: client-area width in pixels * @param height Output: client-area height in pixels */ - void GetSize(int* width, int* height) const; + void GetSize(int* width, int* height) const; - /** + /** * @brief Get the maximum allowed window size * @param width Output: maximum width in pixels * @param height Output: maximum height in pixels */ - void GetMaxSize(int* width, int* height) const; + void GetMaxSize(int* width, int* height) const; - /** + /** * @brief Get the minimum allowed window size * @param width Output: minimum width in pixels * @param height Output: minimum height in pixels */ - void GetMinSize(int* width, int* height) const; + void GetMinSize(int* width, int* height) const; - /** + /** * @brief Get the window title bar text * @return UTF-8 title string; caller must free with InfiniFrame_FreeString */ - [[nodiscard]] AutoString GetTitle() const; + [[nodiscard]] AutoString GetTitle() const; - /** + /** * @brief Get whether the window is always on top of other windows * @param topmost Output: true if the always-on-top flag is set */ - void GetTopmost(bool* topmost) const; + void GetTopmost(bool* topmost) const; - /** + /** * @brief Get the current zoom level * @param zoom Output: zoom percentage (100 = 100%) */ - void GetZoom(int* zoom) const; + void GetZoom(int* zoom) const; - /** + /** * @brief Get whether TLS certificate errors are silently ignored * @param enabled Output: true if certificate errors are suppressed */ - void GetIgnoreCertificateErrorsEnabled(bool* enabled) const; + void GetIgnoreCertificateErrorsEnabled(bool* enabled) const; - /** + /** * @brief Get whether the window currently has keyboard focus * @param isFocused Output: true if the window is the foreground window */ - void GetFocused(bool* isFocused) const; + void GetFocused(bool* isFocused) const; - // ----------------------------------------------------------------------------------------------------------------- - // Navigation - // ----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- + // Navigation + // ----------------------------------------------------------------------------------------------------------------- - /** + /** * @brief Load HTML content directly from a string * @param content UTF-8 HTML source to display */ - void NavigateToString(AutoString content); + void NavigateToString(AutoString content); - /** + /** * @brief Navigate the WebView to a URL * @param url UTF-8 URL to load (http/https or custom scheme) */ - void NavigateToUrl(AutoString url); + void NavigateToUrl(AutoString url); - /** @brief Restore the window from a minimized or maximized state */ - void Restore(); + /** @brief Restore the window from a minimized or maximized state */ + void Restore(); - /** + /** * @brief Post a message string to the web content (received via window.chrome.webview.addEventListener) * @param message UTF-8 message payload */ - void SendWebMessage(AutoString message); + void SendWebMessage(AutoString message); - // ----------------------------------------------------------------------------------------------------------------- - // Set Properties - // ----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- + // Set Properties + // ----------------------------------------------------------------------------------------------------------------- - /** + /** * @brief Enable or disable transparent window background * @param enabled true to enable transparency */ - void SetTransparentEnabled(bool enabled); + void SetTransparentEnabled(bool enabled); - /** + /** * @brief Enable or disable the browser right-click context menu * @param enabled true to show the context menu */ - void SetContextMenuEnabled(bool enabled); + void SetContextMenuEnabled(bool enabled); - /** + /** * @brief Enable or disable user-controlled zoom * @param enabled true to allow pinch/keyboard zoom */ - void SetZoomEnabled(bool enabled); + void SetZoomEnabled(bool enabled); - /** + /** * @brief Enable or disable the browser DevTools panel * @param enabled true to make DevTools accessible */ - void SetDevToolsEnabled(bool enabled); + void SetDevToolsEnabled(bool enabled); - /** + /** * @brief Set the window icon from a file * @param filename UTF-8 path to an image file */ - void SetIconFile(AutoString filename); + void SetIconFile(AutoString filename); - /** + /** * @brief Enter or exit fullscreen mode * @param fullScreen true to go fullscreen, false to restore */ - void SetFullScreen(bool fullScreen); + void SetFullScreen(bool fullScreen); - /** + /** * @brief Maximize or unmaximize the window * @param maximized true to maximize */ - void SetMaximized(bool maximized); + void SetMaximized(bool maximized); - /** + /** * @brief Set the maximum allowed window size * @param width Maximum width in pixels (0 = unlimited) * @param height Maximum height in pixels (0 = unlimited) */ - void SetMaxSize(int width, int height); + void SetMaxSize(int width, int height); - /** + /** * @brief Minimize or restore the window * @param minimized true to minimize */ - void SetMinimized(bool minimized); + void SetMinimized(bool minimized); - /** + /** * @brief Set the minimum allowed window size * @param width Minimum width in pixels * @param height Minimum height in pixels */ - void SetMinSize(int width, int height); + void SetMinSize(int width, int height); - /** + /** * @brief Move the window to screen coordinates * @param x Left edge position in pixels * @param y Top edge position in pixels */ - void SetPosition(int x, int y); + void SetPosition(int x, int y); - /** + /** * @brief Enable or disable user resizing via window border * @param resizable true to allow resizing */ - void SetResizable(bool resizable); + void SetResizable(bool resizable); - /** + /** * @brief Resize the window * @param width New width in pixels * @param height New height in pixels */ - void SetSize(int width, int height); + void SetSize(int width, int height); - /** + /** * @brief Set the window title bar text * @param title UTF-8 title string */ - void SetTitle(AutoString title); + void SetTitle(AutoString title); - /** + /** * @brief Pin or unpin the window above all other windows * @param topmost true to keep always on top */ - void SetTopmost(bool topmost); + void SetTopmost(bool topmost); - /** + /** * @brief Set the WebView zoom level * @param zoom Zoom percentage (e.g. 100 for 100%, 150 for 150%) */ - void SetZoom(int zoom); + void SetZoom(int zoom); - /** @brief Move keyboard focus into the window */ - void SetFocused(); + /** @brief Move keyboard focus into the window */ + void SetFocused(); - // ----------------------------------------------------------------------------------------------------------------- - // Notifications - // ----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- + // Notifications + // ----------------------------------------------------------------------------------------------------------------- - /** + /** * @brief Show a native system notification (toast on Windows, libnotify on Linux, UNUserNotification on macOS) * @param title UTF-8 notification title * @param message UTF-8 notification body text */ - void ShowNotification(AutoString title, AutoString message); + void ShowNotification(AutoString title, AutoString message); - /** + /** * @brief Block the calling thread until the window is closed; runs the platform message loop. * Must be called from the thread that created the window. */ - void WaitForExit(); + void WaitForExit(); - /** @brief Tear down the WebView control while keeping the native window alive */ - void CloseWebView(); + /** @brief Tear down the WebView control while keeping the native window alive */ + void CloseWebView(); - // ----------------------------------------------------------------------------------------------------------------- - // Callbacks - // ----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- + // Callbacks + // ----------------------------------------------------------------------------------------------------------------- - /** + /** * @brief Register a custom URI scheme to be intercepted by WebResourceRequestedCallback * @param scheme UTF-8 scheme name without "://" (e.g. "app") */ - void AddCustomSchemeName(AutoStringConst scheme); + void AddCustomSchemeName(AutoStringConst scheme); - /** + /** * @brief Enumerate all connected monitors by invoking a callback for each one * @param callback Called once per monitor; receives a Monitor describing geometry and scale */ - void GetAllMonitors(GetAllMonitorsCallback callback) const; + void GetAllMonitors(GetAllMonitorsCallback callback) const; - /** + /** * @brief Set callback invoked when the user attempts to close the window * @param callback Returns true to allow closing, false to cancel */ - void SetClosingCallback(ClosingCallback callback); - - /** + void SetClosingCallback(ClosingCallback callback); + + /** * @brief Set callback invoked when the window is closed * @param callback Invoked with no arguments */ - void SetClosedCallback(ClosedCallback callback); + void SetClosedCallback(ClosedCallback callback); - /** + /** * @brief Set callback invoked when the window gains keyboard focus * @param callback Invoked with no arguments */ - void SetFocusInCallback(FocusInCallback callback); + void SetFocusInCallback(FocusInCallback callback); - /** + /** * @brief Set callback invoked when the window loses keyboard focus * @param callback Invoked with no arguments */ - void SetFocusOutCallback(FocusOutCallback callback); + void SetFocusOutCallback(FocusOutCallback callback); - /** + /** * @brief Set callback invoked when the window is moved * @param callback Receives new (x, y) screen coordinates */ - void SetMovedCallback(MovedCallback callback); + void SetMovedCallback(MovedCallback callback); - /** + /** * @brief Set callback invoked when the window is resized * @param callback Receives new (width, height) in pixels */ - void SetResizedCallback(ResizedCallback callback); + void SetResizedCallback(ResizedCallback callback); - /** + /** * @brief Set callback invoked when the window is maximized * @param callback Invoked with no arguments */ - void SetMaximizedCallback(MaximizedCallback callback); + void SetMaximizedCallback(MaximizedCallback callback); - /** + /** * @brief Set callback invoked when the window is restored from maximized state * @param callback Invoked with no arguments */ - void SetRestoredCallback(RestoredCallback callback); + void SetRestoredCallback(RestoredCallback callback); - /** + /** * @brief Set callback invoked when the window is minimized * @param callback Invoked with no arguments */ - void SetMinimizedCallback(MinimizedCallback callback); + void SetMinimizedCallback(MinimizedCallback callback); - /** + /** * @brief Marshal a callback onto the UI thread and execute it synchronously * @param callback Action to invoke on the UI thread */ - void Invoke(ACTION callback); + void Invoke(ACTION callback); - /** + /** * @brief Fire the closing callback * @return true if the window should close, false if the callback cancelled it */ - [[nodiscard]] bool InvokeClose() const noexcept; - - /** @brief Fire the close callback */ - void InvokeClosed() const noexcept; + [[nodiscard]] bool InvokeClose() const noexcept; + + /** @brief Fire the close callback */ + void InvokeClosed() const noexcept; - /** @brief Fire the focus-in callback */ - void InvokeFocusIn() const noexcept; + /** @brief Fire the focus-in callback */ + void InvokeFocusIn() const noexcept; - /** @brief Fire the focus-out callback */ - void InvokeFocusOut() const noexcept; + /** @brief Fire the focus-out callback */ + void InvokeFocusOut() const noexcept; - /** + /** * @brief Fire the moved callback * @param x New left edge in screen pixels * @param y New top edge in screen pixels */ - void InvokeMove(int x, int y) const noexcept; + void InvokeMove(int x, int y) const noexcept; - /** + /** * @brief Fire the resized callback * @param width New width in pixels * @param height New height in pixels */ - void InvokeResize(int width, int height) const noexcept; + void InvokeResize(int width, int height) const noexcept; - /** @brief Fire the maximized callback */ - void InvokeMaximized() const noexcept; + /** @brief Fire the maximized callback */ + void InvokeMaximized() const noexcept; - /** @brief Fire the restored callback */ - void InvokeRestored() const noexcept; + /** @brief Fire the restored callback */ + void InvokeRestored() const noexcept; - /** @brief Fire the minimized callback */ - void InvokeMinimized() const noexcept; + /** @brief Fire the minimized callback */ + void InvokeMinimized() const noexcept; - // ----------------------------------------------------------------------------------------------------------------- - // Platform-specific - // ----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- + // Platform-specific + // ----------------------------------------------------------------------------------------------------------------- #ifdef __linux__ - void OnConfigureEvent(int x, int y, int width, int height); - void OnWindowStateEvent(GdkWindowState newState); + void OnConfigureEvent(int x, int y, int width, int height); + void OnWindowStateEvent(GdkWindowState newState); #endif #ifdef _WIN32 - /** + /** * @brief Register the Win32 window class; must be called once before creating any window * @param hInstance Application instance handle */ - static void Register(HINSTANCE hInstance); + static void Register(HINSTANCE hInstance); - /** + /** * @brief Override the WebView2 fixed-version runtime path * @param pathToWebView2 UTF-8 path to the WebView2 runtime directory */ - static void SetWebView2RuntimePath(AutoString pathToWebView2); + static void SetWebView2RuntimePath(AutoString pathToWebView2); - /** + /** * @brief Get the native Win32 window handle * @return HWND for this window */ - HWND getHwnd(); + HWND getHwnd(); - /** @brief Resize the WebView2 control to fill the current client area */ - void RefitContent(); + /** @brief Resize the WebView2 control to fill the current client area */ + void RefitContent(); - /** @brief Move keyboard focus into the WebView2 control */ - void FocusWebView2(); + /** @brief Move keyboard focus into the WebView2 control */ + void FocusWebView2(); - /** @brief Notify WebView2 that the host window has moved (required to update composition) */ - void NotifyWebView2WindowMove(); + /** @brief Notify WebView2 that the host window has moved (required to update composition) */ + void NotifyWebView2WindowMove(); - /** + /** * @brief Get whether Windows toast notifications are available and registered * @param enabled Output: true if WinToast is initialised and ready */ - void GetNotificationsEnabled(bool* enabled) const; + void GetNotificationsEnabled(bool* enabled) const; - /** + /** * @brief Convert a UTF-8 AutoString to a UTF-16 wide string using simdutf * @param source Null-terminated UTF-8 string * @return std::wstring containing the UTF-16 representation */ - std::wstring ToUTF16String(AutoString source) const; + std::wstring ToUTF16String(AutoString source) const; - /** + /** * @brief Convert a UTF-16 AutoString to a UTF-8 std::string using simdutf * @param source Null-terminated UTF-16 string (passed as AutoString / const char*) * @return std::string containing the UTF-8 representation */ - std::string ToUTF8String(AutoString source) const; + std::string ToUTF8String(AutoString source) const; #elif __APPLE__ - /** + /** * @brief Initialise the NSApplication shared instance; must be called once before creating any window */ - static void Register(); + static void Register(); #endif - // ----------------------------------------------------------------------------------------------------------------- - // Private Implementation (Pimpl) - // ----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- + // Private Implementation (Pimpl) + // ----------------------------------------------------------------------------------------------------------------- - private: - void Show(bool isAlreadyShown); - void AttachWebView(); +private: + void Show(bool isAlreadyShown); + void AttachWebView(); #ifdef _WIN32 - static bool EnsureWebViewIsInstalled(); - static bool InstallWebView2(); + static bool EnsureWebViewIsInstalled(); + static bool InstallWebView2(); #endif #ifdef _WIN32 - friend LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + friend LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); #endif - struct Impl; - std::unique_ptr m_impl; + struct Impl; + std::unique_ptr m_impl; }; #include "InfiniFrameInitParams.h" diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h b/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h index 323c5ec30..24aaa9bea 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h @@ -32,7 +32,7 @@ using WebMessageReceivedCallback = void (*)(AutoString message, AutoString origi * @param outContentType Output: MIME type string (e.g. "text/html") * @return Heap-allocated response body; ownership is transferred to the caller */ -using WebResourceRequestedCallback = void *(*)(AutoString url, int* outNumBytes, AutoString* outContentType); +using WebResourceRequestedCallback = void* (*)(AutoString url, int* outNumBytes, AutoString* outContentType); /** * @brief Called once per monitor during a GetAllMonitors enumeration. diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h b/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h index 570e78ac5..3ed53aef8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h @@ -7,8 +7,7 @@ struct Monitor { struct MonitorRect { int x, y; int width, height; - } monitor, - work; + } monitor, work; double scale; }; diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h index 3c43e0f08..a48d0dcd9 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h @@ -23,7 +23,7 @@ enum class ErrorCode { inline const std::error_category& errorCategory() noexcept { struct InfiniFrameCategory : std::error_category { - const char*name() const noexcept override { + const char* name() const noexcept override { return "InfiniFrame"; } @@ -67,9 +67,7 @@ inline std::error_code make_error_code(const ErrorCode e) noexcept { } namespace std { - template <> - struct is_error_code_enum : true_type { - }; -} +template <> struct is_error_code_enum : true_type {}; +} // namespace std #endif // INFINIFRAME_UTILS_ERROR_CODE_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Event.h b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h index 3fb427af7..c2ca6b2d8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Event.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h @@ -17,139 +17,138 @@ // Event System // --------------------------------------------------------------------------------------------------------------------- -template -class Event { - public: - using Handler = std::function; - using Token = size_t; +template class Event { +public: + using Handler = std::function; + using Token = size_t; - Event() = default; - ~Event() = default; + Event() = default; + ~Event() = default; - Event(const Event&) = delete; - Event& operator=(const Event&) = delete; - Event(Event&&) noexcept = default; - Event& operator=(Event&&) noexcept = default; + Event(const Event&) = delete; + Event& operator=(const Event&) = delete; + Event(Event&&) noexcept = default; + Event& operator=(Event&&) noexcept = default; - /** + /** * @brief Subscribe to event * @param handler Callback function to invoke when event is raised * @return Token for unsubscribing */ - [[nodiscard]] Token Subscribe(Handler handler) { - std::unique_lock lock(m_mutex); - const auto token = m_nextToken++; - m_handlers.emplace(token, std::move(handler)); - return token; - } - - /** + [[nodiscard]] Token Subscribe(Handler handler) { + std::unique_lock lock(m_mutex); + const auto token = m_nextToken++; + m_handlers.emplace(token, std::move(handler)); + return token; + } + + /** * @brief Unsubscribe from event * @param token Token returned from Subscribe */ - void Unsubscribe(Token token) { - std::unique_lock lock(m_mutex); - m_handlers.erase(token); - } + void Unsubscribe(Token token) { + std::unique_lock lock(m_mutex); + m_handlers.erase(token); + } - /** + /** * @brief Raise event (invoke all handlers) * @param args Arguments to pass to handlers */ - void Raise(Args... args) { - std::shared_lock lock(m_mutex); - for (const auto& [_, handler] : m_handlers) { - if (handler) { - handler(args...); - } + void Raise(Args... args) { + std::shared_lock lock(m_mutex); + for (const auto& [_, handler] : m_handlers) { + if (handler) { + handler(args...); } } + } - /** + /** * @brief Check if event has subscribers * @return true if at least one handler is subscribed */ - [[nodiscard]] bool HasSubscribers() const { - std::shared_lock lock(m_mutex); - return !m_handlers.empty(); - } + [[nodiscard]] bool HasSubscribers() const { + std::shared_lock lock(m_mutex); + return !m_handlers.empty(); + } - /** + /** * @brief Clear all subscribers */ - void Clear() { - std::unique_lock lock(m_mutex); - m_handlers.clear(); - } - - private: - mutable std::shared_mutex m_mutex; - std::map m_handlers; - Token m_nextToken = 1; + void Clear() { + std::unique_lock lock(m_mutex); + m_handlers.clear(); + } + +private: + mutable std::shared_mutex m_mutex; + std::map m_handlers; + Token m_nextToken = 1; }; // --------------------------------------------------------------------------------------------------------------------- // Event Subscription Guard // --------------------------------------------------------------------------------------------------------------------- -template -class EventSubscription { - public: - using EventType = Event; - using Token = EventType::Token; +template class EventSubscription { +public: + using EventType = Event; + using Token = EventType::Token; - EventSubscription() = default; + EventSubscription() = default; - EventSubscription(EventType& event, EventType::Handler handler) : - m_event(&event), m_token(event.Subscribe(std::move(handler))) { - } + EventSubscription(EventType& event, EventType::Handler handler) + : m_event(&event) + , m_token(event.Subscribe(std::move(handler))) {} - ~EventSubscription() { - Unsubscribe(); - } + ~EventSubscription() { + Unsubscribe(); + } + + EventSubscription(const EventSubscription&) = delete; + EventSubscription& operator=(const EventSubscription&) = delete; - EventSubscription(const EventSubscription&) = delete; - EventSubscription& operator=(const EventSubscription&) = delete; + EventSubscription(EventSubscription&& other) noexcept + : m_event(other.m_event) + , m_token(other.m_token) { + other.m_event = nullptr; + other.m_token = 0; + } - EventSubscription(EventSubscription&& other) noexcept : - m_event(other.m_event), m_token(other.m_token) { + EventSubscription& operator=(EventSubscription&& other) noexcept { + if (this != &other) { + Unsubscribe(); + m_event = other.m_event; + m_token = other.m_token; other.m_event = nullptr; other.m_token = 0; } + return *this; + } - EventSubscription& operator=(EventSubscription&& other) noexcept { - if (this != &other) { - Unsubscribe(); - m_event = other.m_event; - m_token = other.m_token; - other.m_event = nullptr; - other.m_token = 0; - } - return *this; - } - - /** + /** * @brief Manually unsubscribe from event */ - void Unsubscribe() { - if (m_event && m_token != 0) { - m_event->Unsubscribe(m_token); - m_event = nullptr; - m_token = 0; - } + void Unsubscribe() { + if (m_event && m_token != 0) { + m_event->Unsubscribe(m_token); + m_event = nullptr; + m_token = 0; } + } - /** + /** * @brief Check if subscription is active * @return true if still subscribed */ - [[nodiscard]] bool IsActive() const noexcept { - return m_event != nullptr && m_token != 0; - } + [[nodiscard]] bool IsActive() const noexcept { + return m_event != nullptr && m_token != 0; + } - private: - EventType* m_event = nullptr; - Token m_token = 0; +private: + EventType* m_event = nullptr; + Token m_token = 0; }; #endif // INFINIFRAME_EVENT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h index 894aa7748..422a5480a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h @@ -23,189 +23,167 @@ enum class InteropStatus : int { }; namespace infiniframe::exports { - namespace detail { - inline thread_local std::string g_lastErrorMessage; - inline thread_local InteropStatus g_lastStatus = InteropStatus::Success; +namespace detail { +inline thread_local std::string g_lastErrorMessage; +inline thread_local InteropStatus g_lastStatus = InteropStatus::Success; - inline void SetLastErrorCode(const InteropStatus status) noexcept { +inline void SetLastErrorCode(const InteropStatus status) noexcept { #ifdef _WIN32 - SetLastError(static_cast(status)); + SetLastError(static_cast(status)); #else - errno = static_cast(status); + errno = static_cast(status); #endif - } +} - inline void ClearLastErrorCode() noexcept { +inline void ClearLastErrorCode() noexcept { #ifdef _WIN32 - SetLastError(0); + SetLastError(0); #else - errno = 0; + errno = 0; #endif - } +} - inline void SetFailure(const InteropStatus status, std::string message) noexcept { - g_lastErrorMessage = std::move(message); - g_lastStatus = status; - SetLastErrorCode(status); - } +inline void SetFailure(const InteropStatus status, std::string message) noexcept { + g_lastErrorMessage = std::move(message); + g_lastStatus = status; + SetLastErrorCode(status); +} - inline void SetSuccess() noexcept { - g_lastErrorMessage.clear(); - g_lastStatus = InteropStatus::Success; - ClearLastErrorCode(); - } +inline void SetSuccess() noexcept { + g_lastErrorMessage.clear(); + g_lastStatus = InteropStatus::Success; + ClearLastErrorCode(); +} - inline InteropStatus TranslateException(const std::exception& ex) noexcept { - if (dynamic_cast(&ex) != nullptr) { - SetFailure(InteropStatus::InvalidArgument, ex.what()); - return InteropStatus::InvalidArgument; - } +inline InteropStatus TranslateException(const std::exception& ex) noexcept { + if (dynamic_cast(&ex) != nullptr) { + SetFailure(InteropStatus::InvalidArgument, ex.what()); + return InteropStatus::InvalidArgument; + } - SetFailure(InteropStatus::OperationFailed, ex.what()); - return InteropStatus::OperationFailed; - } + SetFailure(InteropStatus::OperationFailed, ex.what()); + return InteropStatus::OperationFailed; +} #ifdef _WIN32 - inline AutoString AllocateErrorMessageString(const std::string& value) { - if (value.empty()) { - return nullptr; - } - - const int wideCount = MultiByteToWideChar( - CP_UTF8, - 0, - value.c_str(), - static_cast(value.size()), - nullptr, - 0 - ); - if (wideCount <= 0) { - return nullptr; - } - - auto* buffer = new wchar_t[wideCount + 1]; - const int converted = MultiByteToWideChar( - CP_UTF8, - 0, - value.c_str(), - static_cast(value.size()), - buffer, - wideCount - ); - if (converted <= 0) { - delete[] buffer; - return nullptr; - } - - buffer[converted] = L'\0'; - return buffer; - } -#else - inline AutoString AllocateErrorMessageString(const std::string& value) { - if (value.empty()) { - return nullptr; - } - - return AllocateStringCopy(value); - } -#endif +inline AutoString AllocateErrorMessageString(const std::string& value) { + if (value.empty()) { + return nullptr; } - inline AutoString GetLastErrorMessageCopy() { - return detail::AllocateErrorMessageString(detail::g_lastErrorMessage); + const int wideCount = MultiByteToWideChar(CP_UTF8, 0, value.c_str(), static_cast(value.size()), nullptr, 0); + if (wideCount <= 0) { + return nullptr; } - template - inline void ResetOut(T* outValue, const T fallback = {}) noexcept { - if (outValue != nullptr) { - *outValue = fallback; - } + auto* buffer = new wchar_t[wideCount + 1]; + const int converted = + MultiByteToWideChar(CP_UTF8, 0, value.c_str(), static_cast(value.size()), buffer, wideCount); + if (converted <= 0) { + delete[] buffer; + return nullptr; } - template - inline void ResetOut2(T* first, T* second, const T fallback = {}) noexcept { - ResetOut(first, fallback); - ResetOut(second, fallback); + buffer[converted] = L'\0'; + return buffer; +} +#else +inline AutoString AllocateErrorMessageString(const std::string& value) { + if (value.empty()) { + return nullptr; } - template - inline bool EnsureNotNull(T* value, const char* argumentName, const InteropStatus status = InteropStatus::InvalidArgument) noexcept { - if (value != nullptr) { - return true; - } + return AllocateStringCopy(value); +} +#endif +} // namespace detail - detail::SetFailure(status, std::string("Argument '") + argumentName + "' is null."); - return false; - } +inline AutoString GetLastErrorMessageCopy() { + return detail::AllocateErrorMessageString(detail::g_lastErrorMessage); +} - template - inline InteropStatus RunExportStatus(Fn&& fn) noexcept { - try { - detail::SetSuccess(); - std::forward(fn)(); - if (detail::g_lastStatus != InteropStatus::Success) { - return detail::g_lastStatus; - } - detail::SetSuccess(); - return InteropStatus::Success; - } - catch (const std::exception& ex) { - return detail::TranslateException(ex); - } - catch (...) { - detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); - return InteropStatus::OperationFailed; - } +template inline void ResetOut(T* outValue, const T fallback = {}) noexcept { + if (outValue != nullptr) { + *outValue = fallback; } +} - template - inline InteropStatus RunWindowExportStatus(InfiniFrameWindow* instance, Fn&& fn) noexcept { - return RunExportStatus([&] { - if (!EnsureNotNull(instance, "instance")) { - return; - } +template inline void ResetOut2(T* first, T* second, const T fallback = {}) noexcept { + ResetOut(first, fallback); + ResetOut(second, fallback); +} - std::forward(fn)(instance); - }); +template +inline bool EnsureNotNull( + T* value, const char* argumentName, const InteropStatus status = InteropStatus::InvalidArgument +) noexcept { + if (value != nullptr) { + return true; } - template - inline T RunWindowReturnExport(InfiniFrameWindow* instance, T fallback, Fn&& fn) noexcept { - try { - if (!EnsureNotNull(instance, "instance")) { - return fallback; - } + detail::SetFailure(status, std::string("Argument '") + argumentName + "' is null."); + return false; +} - T value = std::forward(fn)(instance); - detail::SetSuccess(); - return value; - } - catch (const std::exception& ex) { - detail::TranslateException(ex); - return fallback; - } - catch (...) { - detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); - return fallback; - } +template inline InteropStatus RunExportStatus(Fn&& fn) noexcept { + try { + detail::SetSuccess(); + std::forward(fn)(); + if (detail::g_lastStatus != InteropStatus::Success) { + return detail::g_lastStatus; + } + detail::SetSuccess(); + return InteropStatus::Success; + } catch (const std::exception& ex) { + return detail::TranslateException(ex); + } catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return InteropStatus::OperationFailed; } +} - template - inline T RunReturnExport(T fallback, Fn&& fn) noexcept { - try { - T value = std::forward(fn)(); - detail::SetSuccess(); - return value; - } - catch (const std::exception& ex) { - detail::TranslateException(ex); - return fallback; +template inline InteropStatus RunWindowExportStatus(InfiniFrameWindow* instance, Fn&& fn) noexcept { + return RunExportStatus([&] { + if (!EnsureNotNull(instance, "instance")) { + return; } - catch (...) { - detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + + std::forward(fn)(instance); + }); +} + +template +inline T RunWindowReturnExport(InfiniFrameWindow* instance, T fallback, Fn&& fn) noexcept { + try { + if (!EnsureNotNull(instance, "instance")) { return fallback; } + + T value = std::forward(fn)(instance); + detail::SetSuccess(); + return value; + } catch (const std::exception& ex) { + detail::TranslateException(ex); + return fallback; + } catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return fallback; + } +} + +template inline T RunReturnExport(T fallback, Fn&& fn) noexcept { + try { + T value = std::forward(fn)(); + detail::SetSuccess(); + return value; + } catch (const std::exception& ex) { + detail::TranslateException(ex); + return fallback; + } catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return fallback; } } +} // namespace infiniframe::exports #endif // INFINIFRAME_EXPORT_GUARDS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Result.h b/src/InfiniFrame.NativeBridge/Native/Utils/Result.h index 3ddc38147..92e8e1a76 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Result.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Result.h @@ -7,7 +7,6 @@ #include "ErrorCode.h" -template -using Result = std::expected; +template using Result = std::expected; #endif // INFINIFRAME_UTILS_RESULT_H From b21e69837eba33d592f0b2817115c08a647a9243 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:15:22 +0200 Subject: [PATCH 21/86] Enhance `native-tidy.ps1` with `ApplyFixes` parameter for better control over auto-fix behavior. --- .gitignore | 1 + src/InfiniFrame.NativeBridge/native-tidy.ps1 | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 6845edc86..8ed5b2ad8 100644 --- a/.gitignore +++ b/.gitignore @@ -346,6 +346,7 @@ healthchecksdb /src/InfiniFrame.NativeBridge/artifacts/ /src/InfiniFrame.NativeBridge/build/ /src/InfiniFrame.NativeBridge/Native/build/ +/src/InfiniFrame.NativeBridge/Native/build-clang-tidy/ /src/InfiniFrame.NativeBridge/Native/packages/ /src/InfiniFrame.NativeBridge/Native/cmake-build-debug/ /src/InfiniFrame.NativeBridge/Native/cmake-build-debug-linux/ diff --git a/src/InfiniFrame.NativeBridge/native-tidy.ps1 b/src/InfiniFrame.NativeBridge/native-tidy.ps1 index 6eae1c4b1..ff58c6b63 100644 --- a/src/InfiniFrame.NativeBridge/native-tidy.ps1 +++ b/src/InfiniFrame.NativeBridge/native-tidy.ps1 @@ -1,5 +1,6 @@ param( [string]$BuildDirectoryName = "build-clang-tidy", + [switch]$ApplyFixes, [switch]$FixErrors ) @@ -57,6 +58,10 @@ $BuildDirectory = Join-Path $NativeRoot $BuildDirectoryName Push-Location $NativeRoot try { + if ($FixErrors -and -not $ApplyFixes) { + $ApplyFixes = $true + } + $clangTidy = Get-Command clang-tidy -ErrorAction SilentlyContinue if (-not $clangTidy) { throw "clang-tidy was not found on PATH." @@ -111,10 +116,14 @@ try { $tidyArgs = @( $sourceFile.FullName, "-p", $BuildDirectory, - "--fix" + "--header-filter=^$" ) - if ($FixErrors) { + if ($ApplyFixes) { + $tidyArgs += "--fix" + } + + if ($ApplyFixes -and $FixErrors) { $tidyArgs += "--fix-errors" } From ce3f00bd945fbcbc2dc321726ead1db209f6d6ea Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:21:40 +0200 Subject: [PATCH 22/86] Update `.clang-format` and `.clang-tidy` for improved consistency in namespace indentation, access modifier alignment, and naming conventions. --- .../Native/.clang-format | 6 +-- .../Native/.clang-tidy | 41 ++++++------------- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-format b/src/InfiniFrame.NativeBridge/Native/.clang-format index 99d6ce4eb..f45ac640a 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-format +++ b/src/InfiniFrame.NativeBridge/Native/.clang-format @@ -16,7 +16,7 @@ DerivePointerAlignment: false PointerAlignment: Left ReferenceAlignment: Left -NamespaceIndentation: None +NamespaceIndentation: All SortIncludes: false SortUsingDeclarations: false @@ -84,8 +84,8 @@ AlignTrailingComments: false # Access Modifiers # ---------------------------------------------------------------------------------------------------------------------- -IndentAccessModifiers: false -AccessModifierOffset: -4 +IndentAccessModifiers: true +AccessModifierOffset: 0 # ---------------------------------------------------------------------------------------------------------------------- # Includes diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-tidy b/src/InfiniFrame.NativeBridge/Native/.clang-tidy index 2e0d41699..351dac4af 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-tidy +++ b/src/InfiniFrame.NativeBridge/Native/.clang-tidy @@ -1,32 +1,15 @@ -Checks: > +Checks: > -*, - - # -------------------------------------------------------------------------------------------------------------------- - # Core Modern C++ - # -------------------------------------------------------------------------------------------------------------------- bugprone-*, cppcoreguidelines-*, modernize-*, performance-*, readability-*, - - # -------------------------------------------------------------------------------------------------------------------- - # Removed / Disabled - # -------------------------------------------------------------------------------------------------------------------- - - # Prefer classic C#-style signatures -modernize-use-trailing-return-type, - - # Often noisy or undesirable in engine code -cppcoreguidelines-pro-bounds-pointer-arithmetic, -cppcoreguidelines-pro-type-reinterpret-cast, -cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-owning-memory, - - # Readability rules that conflict with PascalCase APIs - -readability-identifier-naming, - - # Too aggressive for ECS / low-level engine work -hicpp-*, WarningsAsErrors: '' @@ -42,25 +25,25 @@ CheckOptions: # -------------------------------------------------------------------------------------------------------------------- - key: readability-identifier-naming.ClassCase - value: PascalCase + value: CamelCase - key: readability-identifier-naming.StructCase - value: PascalCase + value: CamelCase - key: readability-identifier-naming.EnumCase - value: PascalCase + value: CamelCase - key: readability-identifier-naming.EnumConstantCase - value: PascalCase + value: CamelCase - key: readability-identifier-naming.FunctionCase - value: PascalCase + value: CamelCase - key: readability-identifier-naming.MethodCase - value: PascalCase + value: CamelCase - key: readability-identifier-naming.NamespaceCase - value: PascalCase + value: CamelCase - key: readability-identifier-naming.VariableCase value: camelBack @@ -69,7 +52,7 @@ CheckOptions: value: camelBack - key: readability-identifier-naming.MemberCase - value: camelBack + value: CamelCase - key: readability-identifier-naming.PrivateMemberPrefix value: _ @@ -84,10 +67,10 @@ CheckOptions: value: camelBack - key: readability-identifier-naming.ConstantCase - value: PascalCase + value: CamelCase - key: readability-identifier-naming.StaticConstantCase - value: PascalCase + value: CamelCase # -------------------------------------------------------------------------------------------------------------------- # Modernization @@ -114,4 +97,4 @@ CheckOptions: # -------------------------------------------------------------------------------------------------------------------- - key: performance-move-const-arg.CheckTriviallyCopyableMove - value: 'false' \ No newline at end of file + value: 'false' From aea16213e3677b2f1a04498026835036607323cc Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:27:55 +0200 Subject: [PATCH 23/86] Update `.clang-format` to disable access modifier indentation for consistency --- src/InfiniFrame.NativeBridge/Native/.clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.clang-format b/src/InfiniFrame.NativeBridge/Native/.clang-format index f45ac640a..da19dd245 100644 --- a/src/InfiniFrame.NativeBridge/Native/.clang-format +++ b/src/InfiniFrame.NativeBridge/Native/.clang-format @@ -84,7 +84,7 @@ AlignTrailingComments: false # Access Modifiers # ---------------------------------------------------------------------------------------------------------------------- -IndentAccessModifiers: true +IndentAccessModifiers: false AccessModifierOffset: 0 # ---------------------------------------------------------------------------------------------------------------------- From 1e28137fab02364dff9a9777fdddfda7ecb8cc78 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:31:55 +0200 Subject: [PATCH 24/86] Enhance `native-tidy.ps1` to support external dependencies with additional `--extra-arg` options, improving compatibility. --- src/InfiniFrame.NativeBridge/native-tidy.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/InfiniFrame.NativeBridge/native-tidy.ps1 b/src/InfiniFrame.NativeBridge/native-tidy.ps1 index ff58c6b63..6d2e04f4c 100644 --- a/src/InfiniFrame.NativeBridge/native-tidy.ps1 +++ b/src/InfiniFrame.NativeBridge/native-tidy.ps1 @@ -54,6 +54,7 @@ function Import-VsDevEnvironment { $NativeRoot = Join-Path $PSScriptRoot "Native" $BuildDirectory = Join-Path $NativeRoot $BuildDirectoryName +$DependenciesRoot = Join-Path $NativeRoot "Dependencies" Push-Location $NativeRoot @@ -116,7 +117,10 @@ try { $tidyArgs = @( $sourceFile.FullName, "-p", $BuildDirectory, - "--header-filter=^$" + "--header-filter=^$", + "--extra-arg=/external:I$DependenciesRoot", + "--extra-arg=/external:W0", + "--extra-arg=-Wno-c++11-narrowing" ) if ($ApplyFixes) { From 9eb02d0ebaa231088e57ed7e70acadc2153c67cc Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:33:07 +0200 Subject: [PATCH 25/86] Refactor variable names in `Embed.InfiniFrameJs.Impl.cmake` and `Embedded.h` for consistent naming conventions. --- .../Native/.cmake/Embed.InfiniFrameJs.Impl.cmake | 8 ++++---- .../Native/Embedded/Embedded.h | 10 +++++----- .../Native/Embedded/InfiniFrameJs/InfiniFrameJs.h | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake index 0ea2fbf01..af672a6c4 100644 --- a/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake +++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake @@ -23,8 +23,8 @@ file(WRITE "${OUTPUT_HEADER}" "#pragma once // ReSharper disable once CppUnusedIncludeDirective #include -extern const unsigned char g_infiniframe_js_data[]; -extern const size_t g_infiniframe_js_size; +extern const unsigned char gInfiniframeJsData[]; +extern const size_t gInfiniframeJsSize; ") # Source file @@ -35,7 +35,7 @@ file(WRITE "${OUTPUT_SOURCE}" "#include \"InfiniFrameJs.h\" // Generated at: ${GENERATED_AT} // ----------------------------------------------------------------------------- -alignas(16) const unsigned char g_infiniframe_js_data[] = {${BYTES}}; +alignas(16) const unsigned char gInfiniframeJsData[] = {${BYTES}}; -const size_t g_infiniframe_js_size = sizeof(g_infiniframe_js_data); +const size_t gInfiniframeJsSize = sizeof(gInfiniframeJsData); ") \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h index 018f115ba..2a3c4ba7a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h @@ -6,12 +6,12 @@ namespace Embedded { inline const std::wstring& InfiniFrameJsUtf16() { static const std::wstring cached = [] { - const auto* src = reinterpret_cast(g_infiniframe_js_data); + const auto* src = reinterpret_cast(gInfiniframeJsData); std::u16string temp; - temp.resize(simdutf::utf16_length_from_utf8(src, g_infiniframe_js_size)); + temp.resize(simdutf::utf16_length_from_utf8(src, gInfiniframeJsSize)); - const size_t written = simdutf::convert_utf8_to_utf16(src, g_infiniframe_js_size, temp.data()); + const size_t written = simdutf::convert_utf8_to_utf16(src, gInfiniframeJsSize, temp.data()); temp.resize(written); @@ -23,8 +23,8 @@ inline const std::wstring& InfiniFrameJsUtf16() { inline const std::string& InfiniFrameJsUtf8() { static const std::string cached = [] { - const auto* src = reinterpret_cast(g_infiniframe_js_data); - return std::string(src, g_infiniframe_js_size); + const auto* src = reinterpret_cast(gInfiniframeJsData); + return std::string(src, gInfiniframeJsSize); }(); return cached; } diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h b/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h index f5a4595d5..4b764b603 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h @@ -2,5 +2,5 @@ // ReSharper disable once CppUnusedIncludeDirective #include -extern const unsigned char g_infiniframe_js_data[]; -extern const size_t g_infiniframe_js_size; +extern const unsigned char gInfiniframeJsData[]; +extern const size_t gInfiniframeJsSize; From 94aa3d4217df1188e306327ae20c1a77e95393eb Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:33:36 +0200 Subject: [PATCH 26/86] Refactor codebase to align access modifiers, namespace indentation, and parameter formatting for consistency throughout. --- .../Native/Embedded/Embedded.h | 36 +-- .../Platform/Linux/Core/UiDispatcher.Gtk.cpp | 34 +-- .../Platform/Linux/Core/WindowSignals.Gtk.cpp | 56 ++-- .../Linux/WebKit/WebKit.Gtk.Internal.h | 6 +- .../Linux/WebKit/WebKitCustomSchemes.Gtk.cpp | 38 +-- .../Linux/WebKit/WebKitMessaging.Gtk.cpp | 60 ++-- .../Windows/Core/WindowLifecycle.Win32.cpp | 54 ++-- .../Native/Platform/Windows/DarkMode.cpp | 36 +-- .../Native/Platform/Windows/Dialog.cpp | 12 +- .../Native/Platform/Windows/ToastHandler.h | 2 +- .../Native/Public/InfiniFrameDialog.h | 4 +- .../Native/Public/InfiniFrameWindow.h | 4 +- .../Native/Utils/ErrorCode.h | 2 +- .../Native/Utils/Event.h | 8 +- .../Native/Utils/ExportGuards.h | 261 +++++++++--------- 15 files changed, 308 insertions(+), 305 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h index 2a3c4ba7a..f123dcebb 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h @@ -4,28 +4,28 @@ #include namespace Embedded { -inline const std::wstring& InfiniFrameJsUtf16() { - static const std::wstring cached = [] { - const auto* src = reinterpret_cast(gInfiniframeJsData); + inline const std::wstring& InfiniFrameJsUtf16() { + static const std::wstring cached = [] { + const auto* src = reinterpret_cast(gInfiniframeJsData); - std::u16string temp; - temp.resize(simdutf::utf16_length_from_utf8(src, gInfiniframeJsSize)); + std::u16string temp; + temp.resize(simdutf::utf16_length_from_utf8(src, gInfiniframeJsSize)); - const size_t written = simdutf::convert_utf8_to_utf16(src, gInfiniframeJsSize, temp.data()); + const size_t written = simdutf::convert_utf8_to_utf16(src, gInfiniframeJsSize, temp.data()); - temp.resize(written); + temp.resize(written); - return std::wstring(temp.begin(), temp.end()); - }(); + return std::wstring(temp.begin(), temp.end()); + }(); - return cached; -} + return cached; + } -inline const std::string& InfiniFrameJsUtf8() { - static const std::string cached = [] { - const auto* src = reinterpret_cast(gInfiniframeJsData); - return std::string(src, gInfiniframeJsSize); - }(); - return cached; -} + inline const std::string& InfiniFrameJsUtf8() { + static const std::string cached = [] { + const auto* src = reinterpret_cast(gInfiniframeJsData); + return std::string(src, gInfiniframeJsSize); + }(); + return cached; + } } // namespace Embedded diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp index 191a3066c..3c98f172e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp @@ -6,24 +6,24 @@ #include "../Window.Gtk.Internal.h" namespace { -std::mutex invokeLockMutex; - -struct InvokeWaitInfo { - ACTION callback; - std::condition_variable completionNotifier; - bool isCompleted; -}; - -gboolean invokeCallback(const gpointer data) { - auto* waitInfo = reinterpret_cast(data); - waitInfo->callback(); - { - std::lock_guard guard(invokeLockMutex); - waitInfo->isCompleted = true; + std::mutex invokeLockMutex; + + struct InvokeWaitInfo { + ACTION callback; + std::condition_variable completionNotifier; + bool isCompleted; + }; + + gboolean invokeCallback(const gpointer data) { + auto* waitInfo = reinterpret_cast(data); + waitInfo->callback(); + { + std::lock_guard guard(invokeLockMutex); + waitInfo->isCompleted = true; + } + waitInfo->completionNotifier.notify_one(); + return false; } - waitInfo->completionNotifier.notify_one(); - return false; -} } // namespace void InfiniFrameWindow::Invoke(const ACTION callback) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp index 262d09c5c..7434c7af5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp @@ -5,38 +5,38 @@ #include "../Window.Gtk.Internal.h" namespace { -bool linux_webview_diagnostics_enabled() { - const char* value = g_getenv("INFINIFRAME_LINUX_WEBVIEW_DIAGNOSTICS"); - return value != nullptr && value[0] != '\0' && g_strcmp0(value, "0") != 0; -} + bool linux_webview_diagnostics_enabled() { + const char* value = g_getenv("INFINIFRAME_LINUX_WEBVIEW_DIAGNOSTICS"); + return value != nullptr && value[0] != '\0' && g_strcmp0(value, "0") != 0; + } -const char* webkit_load_event_to_string(WebKitLoadEvent event) { - switch (event) { - case WEBKIT_LOAD_STARTED: - return "started"; - case WEBKIT_LOAD_REDIRECTED: - return "redirected"; - case WEBKIT_LOAD_COMMITTED: - return "committed"; - case WEBKIT_LOAD_FINISHED: - return "finished"; - default: - return "unknown"; + const char* webkit_load_event_to_string(WebKitLoadEvent event) { + switch (event) { + case WEBKIT_LOAD_STARTED: + return "started"; + case WEBKIT_LOAD_REDIRECTED: + return "redirected"; + case WEBKIT_LOAD_COMMITTED: + return "committed"; + case WEBKIT_LOAD_FINISHED: + return "finished"; + default: + return "unknown"; + } } -} -const char* webkit_termination_reason_to_string(WebKitWebProcessTerminationReason reason) { - switch (reason) { - case WEBKIT_WEB_PROCESS_CRASHED: - return "crashed"; - case WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: - return "exceeded-memory-limit"; - case WEBKIT_WEB_PROCESS_TERMINATED_BY_API: - return "terminated-by-api"; - default: - return "unknown"; + const char* webkit_termination_reason_to_string(WebKitWebProcessTerminationReason reason) { + switch (reason) { + case WEBKIT_WEB_PROCESS_CRASHED: + return "crashed"; + case WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: + return "exceeded-memory-limit"; + case WEBKIT_WEB_PROCESS_TERMINATED_BY_API: + return "terminated-by-api"; + default: + return "unknown"; + } } -} } // namespace void InfiniFrameWindow::OnConfigureEvent(int x, int y, int width, int height) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h index 7ff7044b3..50bb6ee43 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h @@ -6,9 +6,11 @@ #include namespace gtk_webkit { -void HandleWebMessage(WebKitUserContentManager* contentManager, WebKitJavascriptResult* jsResult, gpointer userData); + void HandleWebMessage( + WebKitUserContentManager* contentManager, WebKitJavascriptResult* jsResult, gpointer userData + ); -void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, gpointer userData); + void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, gpointer userData); } // namespace gtk_webkit #endif // INFINIFRAME_PLATFORM_LINUX_WEBKIT_GTK_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp index 0914fe615..772237654 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp @@ -7,26 +7,26 @@ #include "WebKit.Gtk.Internal.h" namespace gtk_webkit { -void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { - WebResourceRequestedCallback webResourceRequestedCallback = - reinterpret_cast(user_data); - if (webResourceRequestedCallback == nullptr) { - GError* error = - g_error_new_literal(G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "No custom scheme handler is registered."); - webkit_uri_scheme_request_finish_error(request, error); - g_error_free(error); - return; - } + void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { + WebResourceRequestedCallback webResourceRequestedCallback = + reinterpret_cast(user_data); + if (webResourceRequestedCallback == nullptr) { + GError* error = + g_error_new_literal(G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "No custom scheme handler is registered."); + webkit_uri_scheme_request_finish_error(request, error); + g_error_free(error); + return; + } - const gchar* uri = webkit_uri_scheme_request_get_uri(request); - int numBytes = 0; - AutoString contentType = nullptr; - void* dotNetResponse = webResourceRequestedCallback(const_cast(uri), &numBytes, &contentType); - GInputStream* stream = g_memory_input_stream_new_from_data(dotNetResponse, numBytes, nullptr); - webkit_uri_scheme_request_finish(request, reinterpret_cast(stream), -1, contentType); - g_object_unref(stream); - free(contentType); -} + const gchar* uri = webkit_uri_scheme_request_get_uri(request); + int numBytes = 0; + AutoString contentType = nullptr; + void* dotNetResponse = webResourceRequestedCallback(const_cast(uri), &numBytes, &contentType); + GInputStream* stream = g_memory_input_stream_new_from_data(dotNetResponse, numBytes, nullptr); + webkit_uri_scheme_request_finish(request, reinterpret_cast(stream), -1, contentType); + g_object_unref(stream); + free(contentType); + } } // namespace gtk_webkit void InfiniFrameWindow::Impl::AddCustomSchemeHandlers() { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp index dfc4c6f90..274f47d76 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp @@ -7,41 +7,41 @@ #include "WebKit.Gtk.Internal.h" namespace gtk_webkit { -void HandleWebMessage( - WebKitUserContentManager* contentManager, WebKitJavascriptResult* jsResult, const gpointer userData -) { - JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); - if (jsc_value_is_string(jsValue)) { - AutoString str_value = jsc_value_to_string(jsValue); - WebMessageReceivedCallback callback = reinterpret_cast(userData); - AutoString originValue = nullptr; - - JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); - JSStringRef script = JSStringCreateWithUTF8CString("window.location.href"); - JSValueRef locationValue = JSEvaluateScript(context, script, nullptr, nullptr, 0, nullptr); - JSStringRelease(script); - - if (locationValue != nullptr) { - JSStringRef locationString = JSValueToStringCopy(context, locationValue, nullptr); - if (locationString != nullptr) { - size_t maxBytes = JSStringGetMaximumUTF8CStringSize(locationString); - originValue = static_cast(g_malloc(maxBytes)); - JSStringGetUTF8CString(locationString, originValue, maxBytes); - JSStringRelease(locationString); + void HandleWebMessage( + WebKitUserContentManager* contentManager, WebKitJavascriptResult* jsResult, const gpointer userData + ) { + JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); + if (jsc_value_is_string(jsValue)) { + AutoString str_value = jsc_value_to_string(jsValue); + WebMessageReceivedCallback callback = reinterpret_cast(userData); + AutoString originValue = nullptr; + + JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); + JSStringRef script = JSStringCreateWithUTF8CString("window.location.href"); + JSValueRef locationValue = JSEvaluateScript(context, script, nullptr, nullptr, 0, nullptr); + JSStringRelease(script); + + if (locationValue != nullptr) { + JSStringRef locationString = JSValueToStringCopy(context, locationValue, nullptr); + if (locationString != nullptr) { + size_t maxBytes = JSStringGetMaximumUTF8CStringSize(locationString); + originValue = static_cast(g_malloc(maxBytes)); + JSStringGetUTF8CString(locationString, originValue, maxBytes); + JSStringRelease(locationString); + } } - } - if (callback != nullptr) { - callback(str_value, originValue); - } + if (callback != nullptr) { + callback(str_value, originValue); + } - if (originValue != nullptr) - g_free(originValue); + if (originValue != nullptr) + g_free(originValue); - g_free(str_value); + g_free(str_value); + } + webkit_javascript_result_unref(jsResult); } - webkit_javascript_result_unref(jsResult); -} } // namespace gtk_webkit #endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp index 9d4353421..3a0d470b3 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp @@ -8,39 +8,39 @@ using namespace WinToastLib; LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); namespace { -class BrushManager { -public: - static BrushManager& instance() noexcept { - static BrushManager inst; - return inst; - } + class BrushManager { + public: + static BrushManager& instance() noexcept { + static BrushManager inst; + return inst; + } - HBRUSH dark() const noexcept { - return static_cast(m_darkBrush.get()); - } + HBRUSH dark() const noexcept { + return static_cast(m_darkBrush.get()); + } - HBRUSH light() const noexcept { - return static_cast(m_lightBrush.get()); - } + HBRUSH light() const noexcept { + return static_cast(m_lightBrush.get()); + } -private: - BrushManager() noexcept { - m_darkBrush.reset(CreateSolidBrush(RGB(0, 0, 0))); - m_lightBrush.reset(CreateSolidBrush(RGB(255, 255, 255))); - } + private: + BrushManager() noexcept { + m_darkBrush.reset(CreateSolidBrush(RGB(0, 0, 0))); + m_lightBrush.reset(CreateSolidBrush(RGB(255, 255, 255))); + } - ~BrushManager() noexcept = default; + ~BrushManager() noexcept = default; - struct HBRUSHDeleter { - void operator()(void* h) const noexcept { - if (h) - DeleteObject(static_cast(h)); - } - }; + struct HBRUSHDeleter { + void operator()(void* h) const noexcept { + if (h) + DeleteObject(static_cast(h)); + } + }; - std::unique_ptr m_darkBrush; - std::unique_ptr m_lightBrush; -}; + std::unique_ptr m_darkBrush; + std::unique_ptr m_lightBrush; + }; } // namespace HBRUSH GetDarkBrush() { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp index 1f75ca4f7..dd012c76e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp @@ -31,30 +31,30 @@ static constexpr DWORD wiN10MinimumBuildDarkMode = 18362; static std::once_flag flagInitDarkModeSupport; namespace { -class ModuleHandle { -public: - ~ModuleHandle() { - if (_handle != nullptr) { - FreeLibrary(_handle); + class ModuleHandle { + public: + ~ModuleHandle() { + if (_handle != nullptr) { + FreeLibrary(_handle); + } } - } - void reset(HMODULE handle) { - if (_handle != nullptr) { - FreeLibrary(_handle); + void reset(HMODULE handle) { + if (_handle != nullptr) { + FreeLibrary(_handle); + } + _handle = handle; } - _handle = handle; - } - auto get() const -> HMODULE { - return _handle; - } + auto get() const -> HMODULE { + return _handle; + } -private: - HMODULE _handle = nullptr; -}; + private: + HMODULE _handle = nullptr; + }; -ModuleHandle gUxtheme; + ModuleHandle gUxtheme; } // namespace static void EnableDarkModeForApp() noexcept { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp index 644b73cc8..e08f6f62b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp @@ -17,7 +17,7 @@ * Used to ensure comdlg32 is available before activating the common-controls activation context */ class Dll { -public: + public: /** @brief Load the named DLL; handle is null if loading fails */ explicit Dll(const std::string& name); /** @brief Unload the DLL if it was loaded successfully */ @@ -28,7 +28,7 @@ class Dll { * @tparam T Function signature (e.g. BOOL(HWND, LPCWSTR)) */ template class Proc { - public: + public: /** * @brief Resolve a symbol from a loaded DLL * @param lib DLL to search @@ -47,11 +47,11 @@ class Dll { return _mProc; } - private: + private: T* _mProc; }; -private: + private: HMODULE _handle; }; @@ -71,13 +71,13 @@ inline Dll::~Dll() { * embedded manifest resource (ID 124) */ class NewStyleContext { -public: + public: /** @brief Activate the Common Controls v6 context */ NewStyleContext(); /** @brief Deactivate the context */ ~NewStyleContext(); -private: + private: /** @brief Create the activation context from shell32.dll's manifest; called once */ static HANDLE Create(); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h index 8bb28d45d..c12bab422 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h @@ -20,7 +20,7 @@ using namespace WinToastLib; class WinToastHandler final : public IWinToastHandler { InfiniFrameWindow* _window; -public: + public: /** * @brief Construct a handler bound to a specific window * @param window The window to bring to the foreground on notification activation diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h index 7c0f1967e..3385abdf9 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h @@ -20,7 +20,7 @@ class InfiniFrameWindow; // forward declaration * @brief Dialog handler for file/folder operations and message boxes */ class InfiniFrameDialog { -public: + public: #ifdef _WIN32 /** * @brief Construct dialog handler with parent window (Windows) @@ -95,7 +95,7 @@ class InfiniFrameDialog { */ DialogResult ShowMessage(AutoString title, AutoString text, DialogButtons buttons, DialogIcon icon); -protected: + protected: #ifdef __APPLE__ NSImage* _errorIcon; NSImage* _infoIcon; diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h index 3e94ede0c..e3d667c39 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h @@ -47,7 +47,7 @@ struct InfiniFrameInitParams; * Supports Windows (Win32 + WebView2), Linux (GTK3 + WebKit2GTK), macOS (Cocoa + WKWebView) */ class InfiniFrameWindow { -public: + public: /** * @brief Construct new InfiniFrame window * @param initParams Initialization parameters @@ -581,7 +581,7 @@ class InfiniFrameWindow { // Private Implementation (Pimpl) // ----------------------------------------------------------------------------------------------------------------- -private: + private: void Show(bool isAlreadyShown); void AttachWebView(); diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h index a48d0dcd9..f4a242ae1 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h @@ -67,7 +67,7 @@ inline std::error_code make_error_code(const ErrorCode e) noexcept { } namespace std { -template <> struct is_error_code_enum : true_type {}; + template <> struct is_error_code_enum : true_type {}; } // namespace std #endif // INFINIFRAME_UTILS_ERROR_CODE_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Event.h b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h index c2ca6b2d8..0972c9066 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Event.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h @@ -18,7 +18,7 @@ // --------------------------------------------------------------------------------------------------------------------- template class Event { -public: + public: using Handler = std::function; using Token = size_t; @@ -81,7 +81,7 @@ template class Event { m_handlers.clear(); } -private: + private: mutable std::shared_mutex m_mutex; std::map m_handlers; Token m_nextToken = 1; @@ -92,7 +92,7 @@ template class Event { // --------------------------------------------------------------------------------------------------------------------- template class EventSubscription { -public: + public: using EventType = Event; using Token = EventType::Token; @@ -146,7 +146,7 @@ template class EventSubscription { return m_event != nullptr && m_token != 0; } -private: + private: EventType* m_event = nullptr; Token m_token = 0; }; diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h index 422a5480a..be26e3315 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h @@ -23,167 +23,168 @@ enum class InteropStatus : int { }; namespace infiniframe::exports { -namespace detail { -inline thread_local std::string g_lastErrorMessage; -inline thread_local InteropStatus g_lastStatus = InteropStatus::Success; + namespace detail { + inline thread_local std::string g_lastErrorMessage; + inline thread_local InteropStatus g_lastStatus = InteropStatus::Success; -inline void SetLastErrorCode(const InteropStatus status) noexcept { + inline void SetLastErrorCode(const InteropStatus status) noexcept { #ifdef _WIN32 - SetLastError(static_cast(status)); + SetLastError(static_cast(status)); #else - errno = static_cast(status); + errno = static_cast(status); #endif -} + } -inline void ClearLastErrorCode() noexcept { + inline void ClearLastErrorCode() noexcept { #ifdef _WIN32 - SetLastError(0); + SetLastError(0); #else - errno = 0; + errno = 0; #endif -} - -inline void SetFailure(const InteropStatus status, std::string message) noexcept { - g_lastErrorMessage = std::move(message); - g_lastStatus = status; - SetLastErrorCode(status); -} - -inline void SetSuccess() noexcept { - g_lastErrorMessage.clear(); - g_lastStatus = InteropStatus::Success; - ClearLastErrorCode(); -} - -inline InteropStatus TranslateException(const std::exception& ex) noexcept { - if (dynamic_cast(&ex) != nullptr) { - SetFailure(InteropStatus::InvalidArgument, ex.what()); - return InteropStatus::InvalidArgument; - } + } - SetFailure(InteropStatus::OperationFailed, ex.what()); - return InteropStatus::OperationFailed; -} + inline void SetFailure(const InteropStatus status, std::string message) noexcept { + g_lastErrorMessage = std::move(message); + g_lastStatus = status; + SetLastErrorCode(status); + } -#ifdef _WIN32 -inline AutoString AllocateErrorMessageString(const std::string& value) { - if (value.empty()) { - return nullptr; - } + inline void SetSuccess() noexcept { + g_lastErrorMessage.clear(); + g_lastStatus = InteropStatus::Success; + ClearLastErrorCode(); + } - const int wideCount = MultiByteToWideChar(CP_UTF8, 0, value.c_str(), static_cast(value.size()), nullptr, 0); - if (wideCount <= 0) { - return nullptr; - } + inline InteropStatus TranslateException(const std::exception& ex) noexcept { + if (dynamic_cast(&ex) != nullptr) { + SetFailure(InteropStatus::InvalidArgument, ex.what()); + return InteropStatus::InvalidArgument; + } - auto* buffer = new wchar_t[wideCount + 1]; - const int converted = - MultiByteToWideChar(CP_UTF8, 0, value.c_str(), static_cast(value.size()), buffer, wideCount); - if (converted <= 0) { - delete[] buffer; - return nullptr; - } + SetFailure(InteropStatus::OperationFailed, ex.what()); + return InteropStatus::OperationFailed; + } - buffer[converted] = L'\0'; - return buffer; -} +#ifdef _WIN32 + inline AutoString AllocateErrorMessageString(const std::string& value) { + if (value.empty()) { + return nullptr; + } + + const int wideCount = + MultiByteToWideChar(CP_UTF8, 0, value.c_str(), static_cast(value.size()), nullptr, 0); + if (wideCount <= 0) { + return nullptr; + } + + auto* buffer = new wchar_t[wideCount + 1]; + const int converted = + MultiByteToWideChar(CP_UTF8, 0, value.c_str(), static_cast(value.size()), buffer, wideCount); + if (converted <= 0) { + delete[] buffer; + return nullptr; + } + + buffer[converted] = L'\0'; + return buffer; + } #else -inline AutoString AllocateErrorMessageString(const std::string& value) { - if (value.empty()) { - return nullptr; - } + inline AutoString AllocateErrorMessageString(const std::string& value) { + if (value.empty()) { + return nullptr; + } - return AllocateStringCopy(value); -} + return AllocateStringCopy(value); + } #endif -} // namespace detail + } // namespace detail -inline AutoString GetLastErrorMessageCopy() { - return detail::AllocateErrorMessageString(detail::g_lastErrorMessage); -} - -template inline void ResetOut(T* outValue, const T fallback = {}) noexcept { - if (outValue != nullptr) { - *outValue = fallback; + inline AutoString GetLastErrorMessageCopy() { + return detail::AllocateErrorMessageString(detail::g_lastErrorMessage); } -} - -template inline void ResetOut2(T* first, T* second, const T fallback = {}) noexcept { - ResetOut(first, fallback); - ResetOut(second, fallback); -} - -template -inline bool EnsureNotNull( - T* value, const char* argumentName, const InteropStatus status = InteropStatus::InvalidArgument -) noexcept { - if (value != nullptr) { - return true; + + template inline void ResetOut(T* outValue, const T fallback = {}) noexcept { + if (outValue != nullptr) { + *outValue = fallback; + } } - detail::SetFailure(status, std::string("Argument '") + argumentName + "' is null."); - return false; -} + template inline void ResetOut2(T* first, T* second, const T fallback = {}) noexcept { + ResetOut(first, fallback); + ResetOut(second, fallback); + } -template inline InteropStatus RunExportStatus(Fn&& fn) noexcept { - try { - detail::SetSuccess(); - std::forward(fn)(); - if (detail::g_lastStatus != InteropStatus::Success) { - return detail::g_lastStatus; + template + inline bool EnsureNotNull( + T* value, const char* argumentName, const InteropStatus status = InteropStatus::InvalidArgument + ) noexcept { + if (value != nullptr) { + return true; } - detail::SetSuccess(); - return InteropStatus::Success; - } catch (const std::exception& ex) { - return detail::TranslateException(ex); - } catch (...) { - detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); - return InteropStatus::OperationFailed; + + detail::SetFailure(status, std::string("Argument '") + argumentName + "' is null."); + return false; } -} -template inline InteropStatus RunWindowExportStatus(InfiniFrameWindow* instance, Fn&& fn) noexcept { - return RunExportStatus([&] { - if (!EnsureNotNull(instance, "instance")) { - return; + template inline InteropStatus RunExportStatus(Fn&& fn) noexcept { + try { + detail::SetSuccess(); + std::forward(fn)(); + if (detail::g_lastStatus != InteropStatus::Success) { + return detail::g_lastStatus; + } + detail::SetSuccess(); + return InteropStatus::Success; + } catch (const std::exception& ex) { + return detail::TranslateException(ex); + } catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return InteropStatus::OperationFailed; } + } + + template inline InteropStatus RunWindowExportStatus(InfiniFrameWindow* instance, Fn&& fn) noexcept { + return RunExportStatus([&] { + if (!EnsureNotNull(instance, "instance")) { + return; + } - std::forward(fn)(instance); - }); -} + std::forward(fn)(instance); + }); + } -template -inline T RunWindowReturnExport(InfiniFrameWindow* instance, T fallback, Fn&& fn) noexcept { - try { - if (!EnsureNotNull(instance, "instance")) { + template + inline T RunWindowReturnExport(InfiniFrameWindow* instance, T fallback, Fn&& fn) noexcept { + try { + if (!EnsureNotNull(instance, "instance")) { + return fallback; + } + + T value = std::forward(fn)(instance); + detail::SetSuccess(); + return value; + } catch (const std::exception& ex) { + detail::TranslateException(ex); + return fallback; + } catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); return fallback; } - - T value = std::forward(fn)(instance); - detail::SetSuccess(); - return value; - } catch (const std::exception& ex) { - detail::TranslateException(ex); - return fallback; - } catch (...) { - detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); - return fallback; } -} - -template inline T RunReturnExport(T fallback, Fn&& fn) noexcept { - try { - T value = std::forward(fn)(); - detail::SetSuccess(); - return value; - } catch (const std::exception& ex) { - detail::TranslateException(ex); - return fallback; - } catch (...) { - detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); - return fallback; + + template inline T RunReturnExport(T fallback, Fn&& fn) noexcept { + try { + T value = std::forward(fn)(); + detail::SetSuccess(); + return value; + } catch (const std::exception& ex) { + detail::TranslateException(ex); + return fallback; + } catch (...) { + detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return fallback; + } } -} } // namespace infiniframe::exports #endif // INFINIFRAME_EXPORT_GUARDS_H From 46771f8ec1eac67c97f769beb890396d046ff1d9 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 22:51:40 +0200 Subject: [PATCH 27/86] Remove redundant include guards across the codebase following the adoption of `#pragma once`. --- .../Platform/Linux/WebKit/WebKit.Gtk.Internal.h | 7 +------ .../Native/Platform/Linux/Window.Gtk.Internal.h | 5 ----- .../Native/Platform/Mac/Window.Cocoa.Internal.h | 5 ----- .../Native/Platform/Windows/Window.Win32.Context.h | 5 ----- .../Native/Platform/Windows/Window.Win32.Internal.h | 5 ----- .../Native/Public/Exports/Exports.h | 5 ----- .../Native/Public/InfiniFrame.h | 5 ----- .../Native/Public/InfiniFrameDialog.h | 5 ----- .../Native/Public/InfiniFrameInitParams.h | 11 ++++------- .../Native/Public/InfiniFrameWindow.h | 7 +------ .../Native/Public/InfiniFrameWindowImpl.h | 5 ----- src/InfiniFrame.NativeBridge/Native/Types/Basic.h | 5 ----- src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h | 5 ----- src/InfiniFrame.NativeBridge/Native/Types/Dialog.h | 4 ---- .../Native/Types/DialogButtons.h | 4 ---- .../Native/Types/DialogIcon.h | 4 ---- .../Native/Types/DialogResult.h | 5 ----- src/InfiniFrame.NativeBridge/Native/Types/Monitor.h | 5 ----- src/InfiniFrame.NativeBridge/Native/Utils/Common.h | 5 ----- .../Native/Utils/Dimensions.h | 5 ----- src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h | 5 ----- src/InfiniFrame.NativeBridge/Native/Utils/Event.h | 5 ----- .../Native/Utils/ExportGuards.h | 7 +------ src/InfiniFrame.NativeBridge/Native/Utils/Result.h | 5 ----- .../Native/Utils/StringCopy.h | 5 ----- .../Native/Utils/WindowsHandles.h | 9 ++------- 26 files changed, 9 insertions(+), 134 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h index 50bb6ee43..4c74bbcb6 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_PLATFORM_LINUX_WEBKIT_GTK_INTERNAL_H -#define INFINIFRAME_PLATFORM_LINUX_WEBKIT_GTK_INTERNAL_H - #include namespace gtk_webkit { @@ -11,6 +8,4 @@ namespace gtk_webkit { ); void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, gpointer userData); -} // namespace gtk_webkit - -#endif // INFINIFRAME_PLATFORM_LINUX_WEBKIT_GTK_INTERNAL_H +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h index 0d7d9142e..cf31e2943 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_PLATFORM_LINUX_WINDOW_GTK_INTERNAL_H -#define INFINIFRAME_PLATFORM_LINUX_WINDOW_GTK_INTERNAL_H - #include #include @@ -41,5 +38,3 @@ struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { void ConnectWindowSignals(InfiniFrameWindow* window); void ConnectWebViewSignals(InfiniFrameWindow* window); }; - -#endif // INFINIFRAME_PLATFORM_LINUX_WINDOW_GTK_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h index 86d05f383..0bfc61030 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.Cocoa.Internal.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_PLATFORM_MAC_WINDOW_COCOA_INTERNAL_H -#define INFINIFRAME_PLATFORM_MAC_WINDOW_COCOA_INTERNAL_H - #include #include @@ -34,5 +31,3 @@ struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { void SetPreference(NSString* key, NSString* value); void AddCustomScheme(const AutoStringConst scheme, WebResourceRequestedCallback requestHandler); }; - -#endif // INFINIFRAME_PLATFORM_MAC_WINDOW_COCOA_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h index c20deba31..53ca4e2dd 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_CONTEXT_H -#define INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_CONTEXT_H - #include #include #include @@ -75,5 +72,3 @@ template inline void ApplyPendingOwnerWindow(TImpl* impl, const impl->_hWnd, impl->_pendingOwnerHwnd, childThreadId, ownerThreadId, reinterpret_cast(previousOwner) ); } - -#endif // INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_CONTEXT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h index 3702fbf47..e69c1dc52 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_INTERNAL_H -#define INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_INTERNAL_H - #include #include @@ -62,5 +59,3 @@ struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { std::unique_ptr _toastHandler; }; - -#endif // INFINIFRAME_PLATFORM_WINDOWS_WINDOW_WIN32_INTERNAL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h index 98790ba46..8ffb199e2 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_PUBLIC_EXPORTS_H -#define INFINIFRAME_PUBLIC_EXPORTS_H - #include "../InfiniFrame.h" #include "../../Utils/ExportGuards.h" @@ -37,5 +34,3 @@ inline AutoString NullToEmpty(const AutoString value) noexcept { #endif return value != nullptr ? value : const_cast(empty); } - -#endif // INFINIFRAME_PUBLIC_EXPORTS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h index cb38411cc..ad153aab7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h @@ -7,9 +7,6 @@ * It is the primary include file for C API consumers. */ -#ifndef INFINIFRAME_H -#define INFINIFRAME_H - // --------------------------------------------------------------------------------------------------------------------- // Core Types // --------------------------------------------------------------------------------------------------------------------- @@ -32,5 +29,3 @@ #include "../Utils/Common.h" #include "../Utils/Event.h" - -#endif // INFINIFRAME_H diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h index 3385abdf9..61b59d1f5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h @@ -4,9 +4,6 @@ * @brief Dialog handlers for file/folder operations and messages */ -#ifndef INFINIFRAME_CORE_DIALOG_H -#define INFINIFRAME_CORE_DIALOG_H - #include "../Types/Basic.h" #include "../Types/Dialog.h" @@ -105,5 +102,3 @@ class InfiniFrameDialog { InfiniFrameWindow* _window; #endif }; - -#endif // INFINIFRAME_CORE_DIALOG_H diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h index e4f9a23de..d69b069cb 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h @@ -4,9 +4,6 @@ * @brief Window initialization parameters */ -#ifndef INFINIFRAME_CORE_INITPARAMS_H -#define INFINIFRAME_CORE_INITPARAMS_H - #include "../Types/Basic.h" #include "../Types/Callbacks.h" @@ -16,6 +13,8 @@ class InfiniFrameWindow; // Forward declaration * @brief Initialization parameters for InfiniFrame window */ struct InfiniFrameInitParams { + static constexpr std::size_t MaxCustomSchemeNames = 16; + // Content AutoString StartString; AutoString StartUrl; @@ -42,7 +41,7 @@ struct InfiniFrameInitParams { MinimizedCallback MinimizedHandler; MovedCallback MovedHandler; WebMessageReceivedCallback WebMessageReceivedHandler; - AutoString CustomSchemeNames[16]; + AutoString CustomSchemeNames[MaxCustomSchemeNames]; // NOLINT(*-avoid-c-arrays) WebResourceRequestedCallback CustomSchemeHandler; // Position and size @@ -81,7 +80,5 @@ struct InfiniFrameInitParams { bool NotificationsEnabled; // Struct size (for version checking) - int Size; + int StructSize; }; - -#endif // INFINIFRAME_CORE_INITPARAMS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h index e3d667c39..d149419b5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h @@ -4,9 +4,6 @@ * @brief Main window class for InfiniFrame */ -#ifndef INFINIFRAME_CORE_WINDOW_H -#define INFINIFRAME_CORE_WINDOW_H - #ifdef _WIN32 #include #include @@ -598,6 +595,4 @@ class InfiniFrameWindow { std::unique_ptr m_impl; }; -#include "InfiniFrameInitParams.h" - -#endif // INFINIFRAME_CORE_WINDOW_H +#include "InfiniFrameInitParams.h" \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h index 6529323e1..2cfe71e1e 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h @@ -12,9 +12,6 @@ * struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { ... platform handles ... }; */ -#ifndef INFINIFRAME_CORE_WINDOWIMPL_H -#define INFINIFRAME_CORE_WINDOWIMPL_H - #include "../Types/Basic.h" #include "../Types/Callbacks.h" #include "InfiniFrameDialog.h" @@ -79,5 +76,3 @@ struct InfiniFrameWindowImpl { InfiniFrameWindow* _parent = nullptr; std::unique_ptr _dialog; }; - -#endif // INFINIFRAME_CORE_WINDOWIMPL_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Basic.h b/src/InfiniFrame.NativeBridge/Native/Types/Basic.h index b33eccc8f..d32e86710 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Basic.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Basic.h @@ -4,9 +4,6 @@ * @brief Basic type definitions for cross-platform interop */ -#ifndef INFINIFRAME_TYPES_BASIC_H -#define INFINIFRAME_TYPES_BASIC_H - #include // --------------------------------------------------------------------------------------------------------------------- @@ -30,5 +27,3 @@ using AutoStringConst = const wchar_t*; using AutoString = char*; using AutoStringConst = const char*; #endif - -#endif // INFINIFRAME_TYPES_BASIC_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h b/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h index 24aaa9bea..b2fac92d7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h @@ -4,9 +4,6 @@ * @brief C-style callback type definitions for interop */ -#ifndef INFINIFRAME_TYPES_CALLBACKS_H -#define INFINIFRAME_TYPES_CALLBACKS_H - #include "Basic.h" #include "Dialog.h" @@ -78,5 +75,3 @@ using FocusInCallback = void (*)(); /** @brief Called when the window loses keyboard focus */ using FocusOutCallback = void (*)(); - -#endif // INFINIFRAME_TYPES_CALLBACKS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h b/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h index 450081abb..335801c80 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h @@ -4,12 +4,8 @@ * @brief Dialog-related types and enums */ -#ifndef INFINIFRAME_TYPES_DIALOG_H -#define INFINIFRAME_TYPES_DIALOG_H - #include "DialogButtons.h" #include "DialogIcon.h" #include "DialogResult.h" #include "Monitor.h" -#endif // INFINIFRAME_TYPES_DIALOG_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h index 5c7ea86d2..44d5dea81 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_TYPES_DIALOG_BUTTONS_H -#define INFINIFRAME_TYPES_DIALOG_BUTTONS_H - enum class DialogButtons { Ok, OkCancel, @@ -12,4 +9,3 @@ enum class DialogButtons { AbortRetryIgnore, }; -#endif // INFINIFRAME_TYPES_DIALOG_BUTTONS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h index 928b1bd66..437a3536b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_TYPES_DIALOG_ICON_H -#define INFINIFRAME_TYPES_DIALOG_ICON_H - enum class DialogIcon { Info, Warning, @@ -10,4 +7,3 @@ enum class DialogIcon { Question, }; -#endif // INFINIFRAME_TYPES_DIALOG_ICON_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h index 10065db08..f82827247 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_TYPES_DIALOG_RESULT_H -#define INFINIFRAME_TYPES_DIALOG_RESULT_H - enum class DialogResult { Cancel = -1, Ok, @@ -12,5 +9,3 @@ enum class DialogResult { Retry, Ignore, }; - -#endif // INFINIFRAME_TYPES_DIALOG_RESULT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h b/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h index 3ed53aef8..f649ccd8d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_TYPES_MONITOR_H -#define INFINIFRAME_TYPES_MONITOR_H - struct Monitor { struct MonitorRect { int x, y; @@ -10,5 +7,3 @@ struct Monitor { } monitor, work; double scale; }; - -#endif // INFINIFRAME_TYPES_MONITOR_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Common.h b/src/InfiniFrame.NativeBridge/Native/Utils/Common.h index 82f92f806..19e7c89cd 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Common.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Common.h @@ -4,13 +4,8 @@ * @brief Compatibility umbrella for common utilities */ -#ifndef INFINIFRAME_COMMON_H -#define INFINIFRAME_COMMON_H - #include "Dimensions.h" #include "ErrorCode.h" #include "Result.h" #include "StringCopy.h" #include "WindowsHandles.h" - -#endif // INFINIFRAME_COMMON_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h b/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h index 0feca8da7..f371f8238 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_UTILS_DIMENSIONS_H -#define INFINIFRAME_UTILS_DIMENSIONS_H - #include inline constexpr int MaxWindowDimension = 10000; @@ -14,5 +11,3 @@ template [[nodiscard]] constexpr T clampDimension(T value, T minVal = MinWindowDimension, T maxVal = MaxWindowDimension) { return std::clamp(value, minVal, maxVal); } - -#endif // INFINIFRAME_UTILS_DIMENSIONS_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h index f4a242ae1..787ea383d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_UTILS_ERROR_CODE_H -#define INFINIFRAME_UTILS_ERROR_CODE_H - #include #include @@ -69,5 +66,3 @@ inline std::error_code make_error_code(const ErrorCode e) noexcept { namespace std { template <> struct is_error_code_enum : true_type {}; } // namespace std - -#endif // INFINIFRAME_UTILS_ERROR_CODE_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Event.h b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h index 0972c9066..d7943c594 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Event.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h @@ -4,9 +4,6 @@ * @brief Modern event handling system with thread safety */ -#ifndef INFINIFRAME_EVENT_H -#define INFINIFRAME_EVENT_H - #include #include #include @@ -150,5 +147,3 @@ template class EventSubscription { EventType* m_event = nullptr; Token m_token = 0; }; - -#endif // INFINIFRAME_EVENT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h index be26e3315..a4a5cc116 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_EXPORT_GUARDS_H -#define INFINIFRAME_EXPORT_GUARDS_H - #include #include #include @@ -185,6 +182,4 @@ namespace infiniframe::exports { return fallback; } } -} // namespace infiniframe::exports - -#endif // INFINIFRAME_EXPORT_GUARDS_H +} diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Result.h b/src/InfiniFrame.NativeBridge/Native/Utils/Result.h index 92e8e1a76..9942e19e9 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Result.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Result.h @@ -1,12 +1,7 @@ #pragma once -#ifndef INFINIFRAME_UTILS_RESULT_H -#define INFINIFRAME_UTILS_RESULT_H - #include #include "ErrorCode.h" template using Result = std::expected; - -#endif // INFINIFRAME_UTILS_RESULT_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h b/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h index 3f63fc2d2..b61cee595 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_UTILS_STRING_COPY_H -#define INFINIFRAME_UTILS_STRING_COPY_H - #include #include #include @@ -40,5 +37,3 @@ inline char* AllocateStringCopy(const std::string& str) { return copy; } #endif - -#endif // INFINIFRAME_UTILS_STRING_COPY_H diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h b/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h index 5f5b0a74f..87c0e2c82 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h @@ -1,8 +1,5 @@ #pragma once -#ifndef INFINIFRAME_UTILS_WINDOWS_HANDLES_H -#define INFINIFRAME_UTILS_WINDOWS_HANDLES_H - #ifdef _WIN32 #include @@ -11,7 +8,7 @@ struct HBRUSHDeleter { void operator()(void* h) const noexcept { if (h) - DeleteObject(static_cast(h)); + DeleteObject(h); } }; @@ -33,6 +30,4 @@ using UniqueHBRUSH = std::unique_ptr; using UniqueHICON = std::unique_ptr; using UniqueHDC = std::unique_ptr; -#endif - -#endif // INFINIFRAME_UTILS_WINDOWS_HANDLES_H +#endif \ No newline at end of file From 4b8f757ed404550f209472108425d0b4fc213616 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 23:01:01 +0200 Subject: [PATCH 28/86] Remove `inline` specifiers from template functions to improve consistency across the codebase. --- .../Native/Platform/Windows/Window.Win32.Context.h | 2 +- .../Native/Public/Exports/Exports.h | 2 +- .../Native/Utils/ExportGuards.h | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h index 53ca4e2dd..cacda332d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h @@ -35,7 +35,7 @@ HWND ResolveParentWindowHandle(InfiniFrameWindow* parent); HBRUSH GetDarkBrush(); HBRUSH GetLightBrush(); -template inline void ApplyPendingOwnerWindow(TImpl* impl, const wchar_t* phase) { +template void ApplyPendingOwnerWindow(TImpl* impl, const wchar_t* phase) { if (impl == nullptr) return; if (impl->_ownerAssigned) diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h index 8ffb199e2..87a47a7df 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h @@ -22,7 +22,7 @@ using infiniframe::exports::RunReturnExport; using infiniframe::exports::RunWindowExportStatus; using infiniframe::exports::RunWindowReturnExport; -template inline bool EnsureOutNotNull(T* value, const char* argumentName) noexcept { +template bool EnsureOutNotNull(T* value, const char* argumentName) noexcept { return infiniframe::exports::EnsureNotNull(value, argumentName, InteropStatus::OutParameterSetToInvalidNull); } diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h index a4a5cc116..d431502f0 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h @@ -100,19 +100,19 @@ namespace infiniframe::exports { return detail::AllocateErrorMessageString(detail::g_lastErrorMessage); } - template inline void ResetOut(T* outValue, const T fallback = {}) noexcept { + template void ResetOut(T* outValue, const T fallback = {}) noexcept { if (outValue != nullptr) { *outValue = fallback; } } - template inline void ResetOut2(T* first, T* second, const T fallback = {}) noexcept { + template void ResetOut2(T* first, T* second, const T fallback = {}) noexcept { ResetOut(first, fallback); ResetOut(second, fallback); } template - inline bool EnsureNotNull( + bool EnsureNotNull( T* value, const char* argumentName, const InteropStatus status = InteropStatus::InvalidArgument ) noexcept { if (value != nullptr) { @@ -123,7 +123,7 @@ namespace infiniframe::exports { return false; } - template inline InteropStatus RunExportStatus(Fn&& fn) noexcept { + template InteropStatus RunExportStatus(Fn&& fn) noexcept { try { detail::SetSuccess(); std::forward(fn)(); @@ -140,7 +140,7 @@ namespace infiniframe::exports { } } - template inline InteropStatus RunWindowExportStatus(InfiniFrameWindow* instance, Fn&& fn) noexcept { + template InteropStatus RunWindowExportStatus(InfiniFrameWindow* instance, Fn&& fn) noexcept { return RunExportStatus([&] { if (!EnsureNotNull(instance, "instance")) { return; @@ -151,7 +151,7 @@ namespace infiniframe::exports { } template - inline T RunWindowReturnExport(InfiniFrameWindow* instance, T fallback, Fn&& fn) noexcept { + T RunWindowReturnExport(InfiniFrameWindow* instance, T fallback, Fn&& fn) noexcept { try { if (!EnsureNotNull(instance, "instance")) { return fallback; @@ -169,7 +169,7 @@ namespace infiniframe::exports { } } - template inline T RunReturnExport(T fallback, Fn&& fn) noexcept { + template T RunReturnExport(T fallback, Fn&& fn) noexcept { try { T value = std::forward(fn)(); detail::SetSuccess(); From 95970bee2502d31984529bd20c742422821f39e3 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 23:04:28 +0200 Subject: [PATCH 29/86] Add `nodejs` installation to `clion-linux-environment.sh` dependencies for enhanced support --- scripts/clion-linux-environment.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/clion-linux-environment.sh b/scripts/clion-linux-environment.sh index 20f3bba93..fa0062915 100644 --- a/scripts/clion-linux-environment.sh +++ b/scripts/clion-linux-environment.sh @@ -13,7 +13,8 @@ sudo apt install -y \ wget \ build-essential \ pkg-config \ - lsb-release + lsb-release \ + nodejs # ---------------------------------------------------------------------------------------------------------------------- # CMake (latest via Kitware) From 456527f89c7ebc58d85857d08e7bf7834df3923a Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 23:06:49 +0200 Subject: [PATCH 30/86] revert --- .../Native/Dependencies/simdutf/simdutf.h | 11125 +++++++++------- 1 file changed, 6010 insertions(+), 5115 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h index 7cb7476d2..65241451c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h +++ b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h @@ -2,7 +2,6 @@ /* begin file include/simdutf.h */ #ifndef SIMDUTF_H #define SIMDUTF_H -#include #include /* begin file include/simdutf/compiler_check.h */ @@ -76,10 +75,11 @@ #include #endif -#ifdef __apple_build_version__ -#if __apple_build_version__ < 14000000 -#define SIMDUTF_SPAN_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to -#endif +#if defined(__apple_build_version__) + #if __apple_build_version__ < 14000000 + #define SIMDUTF_SPAN_DISABLED \ + 1 // apple-clang/13 doesn't support std::convertible_to + #endif #endif #if SIMDUTF_CPLUSPLUS20 @@ -103,8 +103,8 @@ #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) #define SIMDUTF_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#elifdef _WIN32 -#define SIMDUTF_IS_BIG_ENDIAN 0 +#elif defined(_WIN32) + #define SIMDUTF_IS_BIG_ENDIAN 0 #else #if defined(__APPLE__) || \ defined(__FreeBSD__) // defined __BYTE_ORDER__ && defined @@ -282,11 +282,12 @@ _Pragma(SIMDUTF_STRINGIFY(clang attribute push( \ __attribute__((target(T))), apply_to = function))) #define SIMDUTF_UNTARGET_REGION _Pragma("clang attribute pop") -#elifdef __GNUC__ -// GCC is easier -#define SIMDUTF_TARGET_REGION(T) _Pragma("GCC push_options") _Pragma(SIMDUTF_STRINGIFY(GCC target(T))) -#define SIMDUTF_UNTARGET_REGION _Pragma("GCC pop_options") -#endif // clang then gcc + #elif defined(__GNUC__) + // GCC is easier + #define SIMDUTF_TARGET_REGION(T) \ + _Pragma("GCC push_options") _Pragma(SIMDUTF_STRINGIFY(GCC target(T))) + #define SIMDUTF_UNTARGET_REGION _Pragma("GCC pop_options") + #endif // clang then gcc #endif // defined(SIMDUTF_IS_X86_64) || defined(SIMDUTF_IS_LSX) @@ -448,44 +449,46 @@ #define simdutf_log_assert(cond, msg) #endif -#ifdef SIMDUTF_REGULAR_VISUAL_STUDIO -#define SIMDUTF_DEPRECATED __declspec(deprecated) +#if defined(SIMDUTF_REGULAR_VISUAL_STUDIO) + #define SIMDUTF_DEPRECATED __declspec(deprecated) -#define simdutf_really_inline __forceinline // really inline in release mode -#define simdutf_always_inline __forceinline // always inline, no matter what -#define simdutf_never_inline __declspec(noinline) + #define simdutf_really_inline __forceinline // really inline in release mode + #define simdutf_always_inline __forceinline // always inline, no matter what + #define simdutf_never_inline __declspec(noinline) -#define simdutf_unused -#define simdutf_warn_unused + #define simdutf_unused + #define simdutf_warn_unused -#ifndef simdutf_likely -#define simdutf_likely(x) x -#endif -#ifndef simdutf_unlikely -#define simdutf_unlikely(x) x -#endif + #ifndef simdutf_likely + #define simdutf_likely(x) x + #endif + #ifndef simdutf_unlikely + #define simdutf_unlikely(x) x + #endif -#define SIMDUTF_PUSH_DISABLE_WARNINGS __pragma(warning(push)) -#define SIMDUTF_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0)) -#define SIMDUTF_DISABLE_VS_WARNING(WARNING_NUMBER) __pragma(warning(disable : WARNING_NUMBER)) -// Get rid of Intellisense-only warnings (Code Analysis) -// Though __has_include is C++17, it is supported in Visual Studio 2017 or -// better (_MSC_VER>=1910). -#ifdef __has_include -#if __has_include() -#include -#define SIMDUTF_DISABLE_UNDESIRED_WARNINGS SIMDUTF_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS) -#endif -#endif + #define SIMDUTF_PUSH_DISABLE_WARNINGS __pragma(warning(push)) + #define SIMDUTF_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0)) + #define SIMDUTF_DISABLE_VS_WARNING(WARNING_NUMBER) \ + __pragma(warning(disable : WARNING_NUMBER)) + // Get rid of Intellisense-only warnings (Code Analysis) + // Though __has_include is C++17, it is supported in Visual Studio 2017 or + // better (_MSC_VER>=1910). + #ifdef __has_include + #if __has_include() + #include + #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS \ + SIMDUTF_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS) + #endif + #endif -#ifndef SIMDUTF_DISABLE_UNDESIRED_WARNINGS -#define SIMDUTF_DISABLE_UNDESIRED_WARNINGS -#endif + #ifndef SIMDUTF_DISABLE_UNDESIRED_WARNINGS + #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS + #endif -#define SIMDUTF_DISABLE_DEPRECATED_WARNING SIMDUTF_DISABLE_VS_WARNING(4996) -#define SIMDUTF_DISABLE_STRICT_OVERFLOW_WARNING -#define SIMDUTF_POP_DISABLE_WARNINGS __pragma(warning(pop)) -#define SIMDUTF_DISABLE_UNUSED_WARNING + #define SIMDUTF_DISABLE_DEPRECATED_WARNING SIMDUTF_DISABLE_VS_WARNING(4996) + #define SIMDUTF_DISABLE_STRICT_OVERFLOW_WARNING + #define SIMDUTF_POP_DISABLE_WARNINGS __pragma(warning(pop)) + #define SIMDUTF_DISABLE_UNUSED_WARNING #else // SIMDUTF_REGULAR_VISUAL_STUDIO #if defined(__OPTIMIZE__) || defined(NDEBUG) #define simdutf_really_inline inline __attribute__((always_inline)) @@ -526,7 +529,7 @@ #define SIMDUTF_PRAGMA(P) _Pragma(#P) #define SIMDUTF_DISABLE_GCC_WARNING(WARNING) \ SIMDUTF_PRAGMA(GCC diagnostic ignored #WARNING) - #ifdef SIMDUTF_CLANG_VISUAL_STUDIO + #if defined(SIMDUTF_CLANG_VISUAL_STUDIO) #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS \ SIMDUTF_DISABLE_GCC_WARNING(-Wmicrosoft-include) #else @@ -639,11 +642,12 @@ enum endianness { #endif }; -simdutf_warn_unused simdutf_really_inline constexpr auto match_system(endianness e) -> bool { - return e == endianness::NATIVE; +simdutf_warn_unused simdutf_really_inline constexpr bool +match_system(endianness e) { + return e == endianness::NATIVE; } -simdutf_warn_unused auto to_string(encoding_type bom) -> std::string_view; +simdutf_warn_unused std::string_view to_string(encoding_type bom); // Note that BOM for UTF8 is discouraged. namespace BOM { @@ -655,15 +659,15 @@ namespace BOM { * @return the corresponding encoding */ -simdutf_warn_unused auto check_bom(const uint8_t* byte, size_t length) -> encoding_type; -simdutf_warn_unused auto check_bom(const char* byte, size_t length) -> encoding_type; +simdutf_warn_unused encoding_type check_bom(const uint8_t *byte, size_t length); +simdutf_warn_unused encoding_type check_bom(const char *byte, size_t length); /** * Returns the size, in bytes, of the BOM for a given encoding type. * Note that UTF8 BOM are discouraged. * @param bom the encoding type * @return the size in bytes of the corresponding BOM */ -simdutf_warn_unused auto bom_byte_size(encoding_type bom) -> size_t; +simdutf_warn_unused size_t bom_byte_size(encoding_type bom); } // namespace BOM @@ -835,33 +839,33 @@ enum error_code { OTHER // Not related to validation/transcoding. }; -inline auto error_to_string(error_code code) noexcept -> std::string_view { - switch (code) { - case SUCCESS: - return "SUCCESS"; - case HEADER_BITS: - return "HEADER_BITS"; - case TOO_SHORT: - return "TOO_SHORT"; - case TOO_LONG: - return "TOO_LONG"; - case OVERLONG: - return "OVERLONG"; - case TOO_LARGE: - return "TOO_LARGE"; - case SURROGATE: - return "SURROGATE"; - case INVALID_BASE64_CHARACTER: - return "INVALID_BASE64_CHARACTER"; - case BASE64_INPUT_REMAINDER: - return "BASE64_INPUT_REMAINDER"; - case BASE64_EXTRA_BITS: - return "BASE64_EXTRA_BITS"; - case OUTPUT_BUFFER_TOO_SMALL: - return "OUTPUT_BUFFER_TOO_SMALL"; - default: - return "OTHER"; - } +inline std::string_view error_to_string(error_code code) noexcept { + switch (code) { + case SUCCESS: + return "SUCCESS"; + case HEADER_BITS: + return "HEADER_BITS"; + case TOO_SHORT: + return "TOO_SHORT"; + case TOO_LONG: + return "TOO_LONG"; + case OVERLONG: + return "OVERLONG"; + case TOO_LARGE: + return "TOO_LARGE"; + case SURROGATE: + return "SURROGATE"; + case INVALID_BASE64_CHARACTER: + return "INVALID_BASE64_CHARACTER"; + case BASE64_INPUT_REMAINDER: + return "BASE64_INPUT_REMAINDER"; + case BASE64_EXTRA_BITS: + return "BASE64_EXTRA_BITS"; + case OUTPUT_BUFFER_TOO_SMALL: + return "OUTPUT_BUFFER_TOO_SMALL"; + default: + return "OTHER"; + } } struct result { @@ -877,43 +881,40 @@ struct result { size_t pos) noexcept : error{err}, count{pos} {} - [[nodiscard]] simdutf_really_inline simdutf_constexpr23 auto is_ok() const noexcept -> bool { - return error == error_code::SUCCESS; + simdutf_really_inline simdutf_constexpr23 bool is_ok() const noexcept { + return error == error_code::SUCCESS; } - [[nodiscard]] simdutf_really_inline simdutf_constexpr23 auto is_err() const noexcept -> bool { - return error != error_code::SUCCESS; + simdutf_really_inline simdutf_constexpr23 bool is_err() const noexcept { + return error != error_code::SUCCESS; } }; struct full_result { error_code error; size_t input_count; - size_t outputCount; - bool paddingError = false; // true if the error is due to padding, only - // meaningful when error is not SUCCESS + size_t output_count; + bool padding_error = false; // true if the error is due to padding, only + // meaningful when error is not SUCCESS simdutf_really_inline simdutf_constexpr23 full_result() noexcept - : error{error_code::SUCCESS} - , input_count{0} - , outputCount{0} {} - - simdutf_really_inline simdutf_constexpr23 full_result(error_code err, size_t posIn, size_t posOut) noexcept - : error{err} - , input_count{posIn} - , outputCount{posOut} {} - simdutf_really_inline simdutf_constexpr23 full_result(error_code err, size_t posIn, size_t posOut, - bool paddingErr) noexcept - : error{err} - , input_count{posIn} - , outputCount{posOut} - , paddingError{paddingErr} {} + : error{error_code::SUCCESS}, input_count{0}, output_count{0} {} + + simdutf_really_inline simdutf_constexpr23 full_result(error_code err, + size_t pos_in, + size_t pos_out) noexcept + : error{err}, input_count{pos_in}, output_count{pos_out} {} + simdutf_really_inline simdutf_constexpr23 full_result( + error_code err, size_t pos_in, size_t pos_out, bool padding_err) noexcept + : error{err}, input_count{pos_in}, output_count{pos_out}, + padding_error{padding_err} {} simdutf_really_inline simdutf_constexpr23 operator result() const noexcept { if (error == error_code::SUCCESS) { - return result{error, outputCount}; + return result{error, output_count}; + } else { + return result{error, input_count}; } - return result{error, input_count}; } }; @@ -956,8 +957,8 @@ enum { /* begin file include/simdutf/implementation.h */ #ifndef SIMDUTF_IMPLEMENTATION_H #define SIMDUTF_IMPLEMENTATION_H -#ifndef SIMDUTF_NO_THREADS -#include +#if !defined(SIMDUTF_NO_THREADS) + #include #endif #ifdef SIMDUTF_INTERNAL_TESTS #include @@ -1013,8 +1014,8 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#ifdef _MSC_VER -#include +#if defined(_MSC_VER) + #include #elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) #include #endif @@ -1041,7 +1042,8 @@ struct simdutf_riscv_hwprobe { // #define HWCAP_LOONGARCH_LASX (1 << 5) #endif -namespace simdutf::internal { +namespace simdutf { +namespace internal { enum instruction_set { DEFAULT = 0x0, @@ -1068,7 +1070,7 @@ enum instruction_set { LASX = 0x80000, }; -#ifdef __PPC64__ +#if defined(__PPC64__) static inline uint32_t detect_supported_architectures() { return instruction_set::ALTIVEC; @@ -1116,147 +1118,152 @@ namespace cpuid_bit { // Can be found on Intel ISA Reference for CPUID // EAX = 0x01 -constexpr uint32_t pclmulqdq = static_cast(1) << 1; ///< @private bit 1 of ECX for EAX=0x1 -constexpr uint32_t sse42 = static_cast(1) << 20; ///< @private bit 20 of ECX for EAX=0x1 +constexpr uint32_t pclmulqdq = uint32_t(1) + << 1; ///< @private bit 1 of ECX for EAX=0x1 +constexpr uint32_t sse42 = uint32_t(1) + << 20; ///< @private bit 20 of ECX for EAX=0x1 constexpr uint32_t osxsave = - (static_cast(1) << 26) | (static_cast(1) << 27); ///< @private bits 26+27 of ECX for EAX=0x1 + (uint32_t(1) << 26) | + (uint32_t(1) << 27); ///< @private bits 26+27 of ECX for EAX=0x1 // EAX = 0x7f (Structured Extended Feature Flags), ECX = 0x00 (Sub-leaf) // See: "Table 3-8. Information Returned by CPUID Instruction" namespace ebx { -constexpr uint32_t bmi1 = static_cast(1) << 3; -constexpr uint32_t avx2 = static_cast(1) << 5; -constexpr uint32_t bmi2 = static_cast(1) << 8; -constexpr uint32_t avx512f = static_cast(1) << 16; -constexpr uint32_t avx512dq = static_cast(1) << 17; -constexpr uint32_t avx512ifma = static_cast(1) << 21; -constexpr uint32_t avx512cd = static_cast(1) << 28; -constexpr uint32_t avx512bw = static_cast(1) << 30; -constexpr uint32_t avx512vl = static_cast(1) << 31; +constexpr uint32_t bmi1 = uint32_t(1) << 3; +constexpr uint32_t avx2 = uint32_t(1) << 5; +constexpr uint32_t bmi2 = uint32_t(1) << 8; +constexpr uint32_t avx512f = uint32_t(1) << 16; +constexpr uint32_t avx512dq = uint32_t(1) << 17; +constexpr uint32_t avx512ifma = uint32_t(1) << 21; +constexpr uint32_t avx512cd = uint32_t(1) << 28; +constexpr uint32_t avx512bw = uint32_t(1) << 30; +constexpr uint32_t avx512vl = uint32_t(1) << 31; } // namespace ebx namespace ecx { -constexpr uint32_t avx512vbmi = static_cast(1) << 1; -constexpr uint32_t avx512vbmi2 = static_cast(1) << 6; -constexpr uint32_t avx512vnni = static_cast(1) << 11; -constexpr uint32_t avx512bitalg = static_cast(1) << 12; -constexpr uint32_t avx512vpopcnt = static_cast(1) << 14; +constexpr uint32_t avx512vbmi = uint32_t(1) << 1; +constexpr uint32_t avx512vbmi2 = uint32_t(1) << 6; +constexpr uint32_t avx512vnni = uint32_t(1) << 11; +constexpr uint32_t avx512bitalg = uint32_t(1) << 12; +constexpr uint32_t avx512vpopcnt = uint32_t(1) << 14; } // namespace ecx namespace edx { -constexpr uint32_t avx512vp2intersect = static_cast(1) << 8; +constexpr uint32_t avx512vp2intersect = uint32_t(1) << 8; } namespace xcr0_bit { -constexpr uint64_t avx256Saved = static_cast(1) << 2; ///< @private bit 2 = AVX -constexpr uint64_t avx512Saved = static_cast(7) << 5; ///< @private bits 5,6,7 = opmask, ZMM_hi256, hi16_ZMM +constexpr uint64_t avx256_saved = uint64_t(1) << 2; ///< @private bit 2 = AVX +constexpr uint64_t avx512_saved = + uint64_t(7) << 5; ///< @private bits 5,6,7 = opmask, ZMM_hi256, hi16_ZMM } // namespace xcr0_bit } // namespace cpuid_bit } // namespace static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { -#ifdef _MSC_VER - int cpuInfo[4]; - __cpuidex(cpuInfo, *eax, *ecx); - *eax = cpuInfo[0]; - *ebx = cpuInfo[1]; - *ecx = cpuInfo[2]; - *edx = cpuInfo[3]; -#elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) - uint32_t level = *eax; - __get_cpuid(level, eax, ebx, ecx, edx); -#else - uint32_t a = *eax, b, c = *ecx, d; - asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); - *eax = a; - *ebx = b; - *ecx = c; - *edx = d; -#endif + #if defined(_MSC_VER) + int cpu_info[4]; + __cpuidex(cpu_info, *eax, *ecx); + *eax = cpu_info[0]; + *ebx = cpu_info[1]; + *ecx = cpu_info[2]; + *edx = cpu_info[3]; + #elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) + uint32_t level = *eax; + __get_cpuid(level, eax, ebx, ecx, edx); + #else + uint32_t a = *eax, b, c = *ecx, d; + asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); + *eax = a; + *ebx = b; + *ecx = c; + *edx = d; + #endif } -static inline auto xgetbv() -> uint64_t { -#ifdef _MSC_VER - return _xgetbv(0); -#else - uint32_t xcr0_lo, xcr0_hi; - asm volatile("xgetbv\n\t" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0)); - return xcr0_lo | ((uint64_t)xcr0_hi << 32); -#endif +static inline uint64_t xgetbv() { + #if defined(_MSC_VER) + return _xgetbv(0); + #else + uint32_t xcr0_lo, xcr0_hi; + asm volatile("xgetbv\n\t" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0)); + return xcr0_lo | ((uint64_t)xcr0_hi << 32); + #endif } -static inline auto detect_supported_architectures() -> uint32_t { - uint32_t eax = 0; - uint32_t ebx = 0; - uint32_t ecx = 0; - uint32_t edx = 0; - uint32_t hostIsa = 0x0; +static inline uint32_t detect_supported_architectures() { + uint32_t eax; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + uint32_t host_isa = 0x0; - // EBX for EAX=0x1 - eax = 0x1; - cpuid(&eax, &ebx, &ecx, &edx); + // EBX for EAX=0x1 + eax = 0x1; + cpuid(&eax, &ebx, &ecx, &edx); - if ((ecx & cpuid_bit::sse42) != 0u) { - hostIsa |= instruction_set::SSE42; - } + if (ecx & cpuid_bit::sse42) { + host_isa |= instruction_set::SSE42; + } - if ((ecx & cpuid_bit::pclmulqdq) != 0u) { - hostIsa |= instruction_set::PCLMULQDQ; - } + if (ecx & cpuid_bit::pclmulqdq) { + host_isa |= instruction_set::PCLMULQDQ; + } - if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) { - return hostIsa; - } + if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) { + return host_isa; + } - // xgetbv for checking if the OS saves registers - uint64_t xcr0 = xgetbv(); + // xgetbv for checking if the OS saves registers + uint64_t xcr0 = xgetbv(); - if ((xcr0 & cpuid_bit::xcr0_bit::avx256Saved) == 0) { - return hostIsa; - } - // ECX for EAX=0x7 - eax = 0x7; - ecx = 0x0; // Sub-leaf = 0 - cpuid(&eax, &ebx, &ecx, &edx); - if ((ebx & cpuid_bit::ebx::avx2) != 0u) { - hostIsa |= instruction_set::AVX2; - } - if ((ebx & cpuid_bit::ebx::bmi1) != 0u) { - hostIsa |= instruction_set::BMI1; - } - if ((ebx & cpuid_bit::ebx::bmi2) != 0u) { - hostIsa |= instruction_set::BMI2; - } - if (!((xcr0 & cpuid_bit::xcr0_bit::avx512Saved) == cpuid_bit::xcr0_bit::avx512Saved)) { - return hostIsa; - } - if ((ebx & cpuid_bit::ebx::avx512f) != 0u) { - hostIsa |= instruction_set::AVX512F; - } - if ((ebx & cpuid_bit::ebx::avx512bw) != 0u) { - hostIsa |= instruction_set::AVX512BW; - } - if ((ebx & cpuid_bit::ebx::avx512cd) != 0u) { - hostIsa |= instruction_set::AVX512CD; - } - if ((ebx & cpuid_bit::ebx::avx512dq) != 0u) { - hostIsa |= instruction_set::AVX512DQ; - } - if ((ebx & cpuid_bit::ebx::avx512vl) != 0u) { - hostIsa |= instruction_set::AVX512VL; - } - if ((ecx & cpuid_bit::ecx::avx512vbmi2) != 0u) { - hostIsa |= instruction_set::AVX512VBMI2; - } - if ((ecx & cpuid_bit::ecx::avx512vpopcnt) != 0u) { - hostIsa |= instruction_set::AVX512VPOPCNTDQ; - } - return hostIsa; + if ((xcr0 & cpuid_bit::xcr0_bit::avx256_saved) == 0) { + return host_isa; + } + // ECX for EAX=0x7 + eax = 0x7; + ecx = 0x0; // Sub-leaf = 0 + cpuid(&eax, &ebx, &ecx, &edx); + if (ebx & cpuid_bit::ebx::avx2) { + host_isa |= instruction_set::AVX2; + } + if (ebx & cpuid_bit::ebx::bmi1) { + host_isa |= instruction_set::BMI1; + } + if (ebx & cpuid_bit::ebx::bmi2) { + host_isa |= instruction_set::BMI2; + } + if (!((xcr0 & cpuid_bit::xcr0_bit::avx512_saved) == + cpuid_bit::xcr0_bit::avx512_saved)) { + return host_isa; + } + if (ebx & cpuid_bit::ebx::avx512f) { + host_isa |= instruction_set::AVX512F; + } + if (ebx & cpuid_bit::ebx::avx512bw) { + host_isa |= instruction_set::AVX512BW; + } + if (ebx & cpuid_bit::ebx::avx512cd) { + host_isa |= instruction_set::AVX512CD; + } + if (ebx & cpuid_bit::ebx::avx512dq) { + host_isa |= instruction_set::AVX512DQ; + } + if (ebx & cpuid_bit::ebx::avx512vl) { + host_isa |= instruction_set::AVX512VL; + } + if (ecx & cpuid_bit::ecx::avx512vbmi2) { + host_isa |= instruction_set::AVX512VBMI2; + } + if (ecx & cpuid_bit::ecx::avx512vpopcnt) { + host_isa |= instruction_set::AVX512VPOPCNTDQ; + } + return host_isa; } -#elifdef __loongarch__ +#elif defined(__loongarch__) static inline uint32_t detect_supported_architectures() { uint32_t host_isa = instruction_set::DEFAULT; -#if defined(__linux__) + #if defined(__linux__) uint64_t hwcap = 0; hwcap = getauxval(AT_HWCAP); if (hwcap & HWCAP_LOONGARCH_LSX) { @@ -1265,7 +1272,7 @@ static inline uint32_t detect_supported_architectures() { if (hwcap & HWCAP_LOONGARCH_LASX) { host_isa |= instruction_set::LASX; } -#endif + #endif return host_isa; } #else // fallback @@ -1277,7 +1284,8 @@ static inline uint32_t detect_supported_architectures() { #endif // end SIMD extension detection code -} // namespace simdutf::internal +} // namespace internal +} // namespace simdutf #endif // SIMDutf_INTERNAL_ISADETECTION_H /* end file include/simdutf/internal/isadetection.h */ @@ -1328,7 +1336,8 @@ static inline uint32_t detect_supported_architectures() { #include -namespace simdutf::detail { +namespace simdutf { +namespace detail { /** * The constexpr_ptr class is a workaround for reinterpret_cast not being * allowed during constant evaluation. @@ -1340,56 +1349,54 @@ struct constexpr_ptr { constexpr explicit constexpr_ptr(const from *ptr) noexcept : p(ptr) {} - constexpr auto operator*() const noexcept -> to { - return static_cast(*p); - } + constexpr to operator*() const noexcept { return static_cast(*p); } - constexpr auto operator++() noexcept -> constexpr_ptr& { - ++p; - return *this; + constexpr constexpr_ptr &operator++() noexcept { + ++p; + return *this; } - constexpr auto operator++(int) noexcept -> constexpr_ptr { - auto old = *this; - ++p; - return old; + constexpr constexpr_ptr operator++(int) noexcept { + auto old = *this; + ++p; + return old; } - constexpr auto operator--() noexcept -> constexpr_ptr& { - --p; - return *this; + constexpr constexpr_ptr &operator--() noexcept { + --p; + return *this; } - constexpr auto operator--(int) noexcept -> constexpr_ptr { - auto old = *this; - --p; - return old; + constexpr constexpr_ptr operator--(int) noexcept { + auto old = *this; + --p; + return old; } - constexpr auto operator+=(std::ptrdiff_t n) noexcept -> constexpr_ptr& { - p += n; - return *this; + constexpr constexpr_ptr &operator+=(std::ptrdiff_t n) noexcept { + p += n; + return *this; } - constexpr auto operator-=(std::ptrdiff_t n) noexcept -> constexpr_ptr& { - p -= n; - return *this; + constexpr constexpr_ptr &operator-=(std::ptrdiff_t n) noexcept { + p -= n; + return *this; } - constexpr auto operator+(std::ptrdiff_t n) const noexcept -> constexpr_ptr { - return constexpr_ptr{p + n}; + constexpr constexpr_ptr operator+(std::ptrdiff_t n) const noexcept { + return constexpr_ptr{p + n}; } - constexpr auto operator-(std::ptrdiff_t n) const noexcept -> constexpr_ptr { - return constexpr_ptr{p - n}; + constexpr constexpr_ptr operator-(std::ptrdiff_t n) const noexcept { + return constexpr_ptr{p - n}; } - constexpr auto operator-(const constexpr_ptr& o) const noexcept -> std::ptrdiff_t { - return p - o.p; + constexpr std::ptrdiff_t operator-(const constexpr_ptr &o) const noexcept { + return p - o.p; } - constexpr auto operator[](std::ptrdiff_t n) const noexcept -> to { - return static_cast(*(p + n)); + constexpr to operator[](std::ptrdiff_t n) const noexcept { + return static_cast(*(p + n)); } // to prevent compilation errors for memcpy, even if it is never @@ -1397,8 +1404,9 @@ struct constexpr_ptr { constexpr operator const void *() const noexcept { return p; } }; -template constexpr auto constexpr_cast_ptr(from* p) noexcept -> constexpr_ptr { - return constexpr_ptr{p}; +template +constexpr constexpr_ptr constexpr_cast_ptr(from *p) noexcept { + return constexpr_ptr{p}; } /** @@ -1410,9 +1418,9 @@ struct constexpr_write_ptr_proxy { constexpr explicit constexpr_write_ptr_proxy(TargetType *raw) : p(raw) {} - constexpr auto operator=(SrcType v) -> constexpr_write_ptr_proxy& { - *p = static_cast(v); - return *this; + constexpr constexpr_write_ptr_proxy &operator=(SrcType v) { + *p = static_cast(v); + return *this; } TargetType *p; @@ -1426,27 +1434,28 @@ struct constexpr_write_ptr_proxy { template struct constexpr_write_ptr { constexpr explicit constexpr_write_ptr(TargetType *raw) : p(raw) {} - constexpr auto operator*() const -> constexpr_write_ptr_proxy { - return constexpr_write_ptr_proxy{p}; + constexpr constexpr_write_ptr_proxy operator*() const { + return constexpr_write_ptr_proxy{p}; } - constexpr auto operator[](std::ptrdiff_t n) const -> constexpr_write_ptr_proxy { - return constexpr_write_ptr_proxy{p + n}; + constexpr constexpr_write_ptr_proxy + operator[](std::ptrdiff_t n) const { + return constexpr_write_ptr_proxy{p + n}; } - constexpr auto operator++() -> constexpr_write_ptr& { - ++p; - return *this; + constexpr constexpr_write_ptr &operator++() { + ++p; + return *this; } - constexpr auto operator++(int) -> constexpr_write_ptr { - constexpr_write_ptr old = *this; - ++p; - return old; + constexpr constexpr_write_ptr operator++(int) { + constexpr_write_ptr old = *this; + ++p; + return old; } - constexpr auto operator-(const constexpr_write_ptr& other) const -> std::ptrdiff_t { - return p - other.p; + constexpr std::ptrdiff_t operator-(const constexpr_write_ptr &other) const { + return p - other.p; } TargetType *p; @@ -1457,16 +1466,16 @@ constexpr auto constexpr_cast_writeptr(TargetType *raw) { return constexpr_write_ptr{raw}; } -} // namespace simdutf::detail - +} // namespace detail +} // namespace simdutf #endif /* end file include/simdutf/constexpr_ptr.h */ #endif #if SIMDUTF_SPAN /// helpers placed in namespace detail are not a part of the public API - -namespace simdutf::detail { +namespace simdutf { +namespace detail { /** * matches a byte, in the many ways C++ allows. note that these * are all distinct types. @@ -1541,8 +1550,8 @@ template concept indexes_into_uint32 = requires(InputPtr p) { { std::decay_t{} } -> std::same_as; }; -} // namespace simdutf::detail - +} // namespace detail +} // namespace simdutf #endif // SIMDUTF_SPAN // these includes are needed for constexpr support. they are @@ -1551,32 +1560,36 @@ concept indexes_into_uint32 = requires(InputPtr p) { #ifndef SIMDUTF_SWAP_BYTES_H #define SIMDUTF_SWAP_BYTES_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { -constexpr simdutf_warn_unused auto u16_swap_bytes(const uint16_t word) -> uint16_t { - return static_cast((word >> 8) | (word << 8)); +constexpr inline simdutf_warn_unused uint16_t +u16_swap_bytes(const uint16_t word) { + return uint16_t((word >> 8) | (word << 8)); } -constexpr simdutf_warn_unused auto u32_swap_bytes(const uint32_t word) -> uint32_t { - return ((word >> 24) & 0xff) | // move byte 3 to byte 0 - ((word << 8) & 0xff0000) | // move byte 1 to byte 2 - ((word >> 8) & 0xff00) | // move byte 2 to byte 1 - ((word << 24) & 0xff000000); // byte 0 to byte 3 +constexpr inline simdutf_warn_unused uint32_t +u32_swap_bytes(const uint32_t word) { + return ((word >> 24) & 0xff) | // move byte 3 to byte 0 + ((word << 8) & 0xff0000) | // move byte 1 to byte 2 + ((word >> 8) & 0xff00) | // move byte 2 to byte 1 + ((word << 24) & 0xff000000); // byte 0 to byte 3 } namespace utf32 { -template constexpr auto swap_if_needed(uint32_t c) -> uint32_t { - return !match_system(big_endian) ? scalar::u32_swap_bytes(c) : c; +template constexpr uint32_t swap_if_needed(uint32_t c) { + return !match_system(big_endian) ? scalar::u32_swap_bytes(c) : c; } } // namespace utf32 namespace utf16 { -template constexpr auto swap_if_needed(uint16_t c) -> uint16_t { - return !match_system(big_endian) ? scalar::u16_swap_bytes(c) : c; +template constexpr uint16_t swap_if_needed(uint16_t c) { + return !match_system(big_endian) ? scalar::u16_swap_bytes(c) : c; } } // namespace utf16 -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/swap_bytes.h */ @@ -1584,15 +1597,17 @@ template constexpr auto swap_if_needed(uint16_t c) -> ui #ifndef SIMDUTF_ASCII_H #define SIMDUTF_ASCII_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace ascii { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_warn_unused simdutf_constexpr23 auto validate(InputPtr data, size_t len) noexcept -> bool { +simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, + size_t len) noexcept { uint64_t pos = 0; #if SIMDUTF_CPLUSPLUS23 @@ -1602,14 +1617,14 @@ simdutf_warn_unused simdutf_constexpr23 auto validate(InputPtr data, size_t len) // process in blocks of 16 bytes when possible { for (; pos + 16 <= len; pos += 16) { - uint64_t v1 = 0; - std::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) != 0) { - return false; - } + uint64_t v1; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) != 0) { + return false; + } } } @@ -1623,9 +1638,10 @@ simdutf_warn_unused simdutf_constexpr23 auto validate(InputPtr data, size_t len) } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(InputPtr data, size_t len) noexcept -> result { +simdutf_warn_unused simdutf_constexpr23 result +validate_with_errors(InputPtr data, size_t len) noexcept { size_t pos = 0; #if SIMDUTF_CPLUSPLUS23 // avoid memcpy during constant evaluation @@ -1634,17 +1650,17 @@ simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(InputPtr data, { // process in blocks of 16 bytes when possible for (; pos + 16 <= len; pos += 16) { - uint64_t v1 = 0; - std::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) != 0) { - for (; pos < len; pos++) { - if (static_cast(data[pos]) >= 0b10000000) { - return {error_code::TOO_LARGE, pos}; - } - } + uint64_t v1; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) != 0) { + for (; pos < len; pos++) { + if (static_cast(data[pos]) >= 0b10000000) { + return result(error_code::TOO_LARGE, pos); + } + } } } } @@ -1652,15 +1668,16 @@ simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(InputPtr data, // process the tail byte-by-byte for (; pos < len; pos++) { if (static_cast(data[pos]) >= 0b10000000) { - return {error_code::TOO_LARGE, pos}; + return result(error_code::TOO_LARGE, pos); } } - return {error_code::SUCCESS, pos}; + return result(error_code::SUCCESS, pos); } } // namespace ascii } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/ascii.h */ @@ -1669,8 +1686,8 @@ simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(InputPtr data, #define SIMDUTF_ATOMIC_UTIL_H #if SIMDUTF_ATOMIC_REF #include - -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { // This function is a memcpy that uses atomic operations to read from the // source. @@ -1683,36 +1700,39 @@ inline void memcpy_atomic_read(char *dst, const char *src, size_t len) { constexpr size_t alignment = sizeof(uint64_t); // Lambda for atomic byte-by-byte copy - auto bbbMemcpyAtomicRead = [](char* bytedst, const char* bytesrc, size_t bytelen) noexcept -> void { - char* mutableSrc = const_cast(bytesrc); - for (size_t j = 0; j < bytelen; ++j) { - bytedst[j] = std::atomic_ref(mutableSrc[j]).load(std::memory_order_relaxed); - } + auto bbb_memcpy_atomic_read = [](char *bytedst, const char *bytesrc, + size_t bytelen) noexcept { + char *mutable_src = const_cast(bytesrc); + for (size_t j = 0; j < bytelen; ++j) { + bytedst[j] = + std::atomic_ref(mutable_src[j]).load(std::memory_order_relaxed); + } }; // Handle unaligned start size_t offset = reinterpret_cast(src) % alignment; - if (offset != 0u) { - size_t toAlign = std::min(len, alignment - offset); - bbbMemcpyAtomicRead(dst, src, toAlign); - src += toAlign; - dst += toAlign; - len -= toAlign; + if (offset) { + size_t to_align = std::min(len, alignment - offset); + bbb_memcpy_atomic_read(dst, src, to_align); + src += to_align; + dst += to_align; + len -= to_align; } // Process aligned 64-bit chunks while (len >= alignment) { - auto* srcAligned = reinterpret_cast(const_cast(src)); - const auto dstValue = std::atomic_ref(*srcAligned).load(std::memory_order_relaxed); - std::memcpy(dst, &dstValue, sizeof(uint64_t)); - src += alignment; - dst += alignment; - len -= alignment; + auto *src_aligned = reinterpret_cast(const_cast(src)); + const auto dst_value = + std::atomic_ref(*src_aligned).load(std::memory_order_relaxed); + std::memcpy(dst, &dst_value, sizeof(uint64_t)); + src += alignment; + dst += alignment; + len -= alignment; } // Handle remaining bytes - if (len != 0u) { - bbbMemcpyAtomicRead(dst, src, len); + if (len) { + bbb_memcpy_atomic_read(dst, src, len); } } @@ -1728,40 +1748,43 @@ inline void memcpy_atomic_write(char *dst, const char *src, size_t len) { constexpr size_t alignment = sizeof(uint64_t); // Lambda for atomic byte-by-byte write - auto bbbMemcpyAtomicWrite = [](char* bytedst, const char* bytesrc, size_t bytelen) noexcept -> void { - for (size_t j = 0; j < bytelen; ++j) { - std::atomic_ref(bytedst[j]).store(bytesrc[j], std::memory_order_relaxed); - } + auto bbb_memcpy_atomic_write = [](char *bytedst, const char *bytesrc, + size_t bytelen) noexcept { + for (size_t j = 0; j < bytelen; ++j) { + std::atomic_ref(bytedst[j]) + .store(bytesrc[j], std::memory_order_relaxed); + } }; // Handle unaligned start size_t offset = reinterpret_cast(dst) % alignment; - if (offset != 0u) { - size_t toAlign = std::min(len, alignment - offset); - bbbMemcpyAtomicWrite(dst, src, toAlign); - dst += toAlign; - src += toAlign; - len -= toAlign; + if (offset) { + size_t to_align = std::min(len, alignment - offset); + bbb_memcpy_atomic_write(dst, src, to_align); + dst += to_align; + src += to_align; + len -= to_align; } // Process aligned 64-bit chunks while (len >= alignment) { - auto* dstAligned = reinterpret_cast(dst); - uint64_t srcVal = 0; - std::memcpy(&srcVal, src, sizeof(uint64_t)); // Non-atomic read from src - std::atomic_ref(*dstAligned).store(srcVal, std::memory_order_relaxed); - dst += alignment; - src += alignment; - len -= alignment; + auto *dst_aligned = reinterpret_cast(dst); + uint64_t src_val; + std::memcpy(&src_val, src, sizeof(uint64_t)); // Non-atomic read from src + std::atomic_ref(*dst_aligned) + .store(src_val, std::memory_order_relaxed); + dst += alignment; + src += alignment; + len -= alignment; } // Handle remaining bytes - if (len != 0u) { - bbbMemcpyAtomicWrite(dst, src, len); + if (len) { + bbb_memcpy_atomic_write(dst, src, len); } } -} // namespace simdutf::scalar - +} // namespace scalar +} // namespace simdutf #endif // SIMDUTF_ATOMIC_REF #endif // SIMDUTF_ATOMIC_UTIL_H /* end file include/simdutf/scalar/atomic_util.h */ @@ -1769,24 +1792,27 @@ inline void memcpy_atomic_write(char *dst, const char *src, size_t len) { #ifndef SIMDUTF_LATIN1_H #define SIMDUTF_LATIN1_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace latin1 { -simdutf_really_inline auto utf8_length_from_latin1(const char* buf, size_t len) -> size_t { - const auto* c = reinterpret_cast(buf); - size_t answer = 0; - for (size_t i = 0; i < len; i++) { - if ((c[i] >> 7) != 0) { - answer++; - } +simdutf_really_inline size_t utf8_length_from_latin1(const char *buf, + size_t len) { + const uint8_t *c = reinterpret_cast(buf); + size_t answer = 0; + for (size_t i = 0; i < len; i++) { + if ((c[i] >> 7)) { + answer++; } - return answer + len; + } + return answer + len; } } // namespace latin1 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/latin1.h */ @@ -1794,46 +1820,53 @@ simdutf_really_inline auto utf8_length_from_latin1(const char* buf, size_t len) #ifndef SIMDUTF_LATIN1_TO_UTF16_H #define SIMDUTF_LATIN1_TO_UTF16_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace latin1_to_utf16 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, char16_t* utf16Output) -> size_t { +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + char16_t *utf16_output) { size_t pos = 0; - char16_t* start{utf16Output}; + char16_t *start{utf16_output}; while (pos < len) { uint16_t word = uint8_t(data[pos]); // extend Latin-1 char to 16-bit Unicode code point - *utf16Output++ = char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); + *utf16_output++ = + char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); pos++; } - return utf16Output - start; + return utf16_output - start; } template -inline auto convert_with_errors(const char* buf, size_t len, char16_t* utf16Output) -> result { - const auto* data = reinterpret_cast(buf); - size_t pos = 0; - char16_t* start{utf16Output}; - - while (pos < len) { - auto word = static_cast(data[pos]); // extend Latin-1 char to 16-bit Unicode code point - *utf16Output++ = char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); - pos++; - } +inline result convert_with_errors(const char *buf, size_t len, + char16_t *utf16_output) { + const uint8_t *data = reinterpret_cast(buf); + size_t pos = 0; + char16_t *start{utf16_output}; + + while (pos < len) { + uint16_t word = + uint16_t(data[pos]); // extend Latin-1 char to 16-bit Unicode code point + *utf16_output++ = + char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); + pos++; + } - return {error_code::SUCCESS, utf16Output - start}; + return result(error_code::SUCCESS, utf16_output - start); } } // namespace latin1_to_utf16 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/latin1_to_utf16/latin1_to_utf16.h */ @@ -1841,25 +1874,28 @@ inline auto convert_with_errors(const char* buf, size_t len, char16_t* utf16Outp #ifndef SIMDUTF_LATIN1_TO_UTF32_H #define SIMDUTF_LATIN1_TO_UTF32_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace latin1_to_utf32 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, char32_t* utf32Output) -> size_t { - char32_t* start{utf32Output}; - for (size_t i = 0; i < len; i++) { - *utf32Output++ = uint8_t(data[i]); - } - return utf32Output - start; +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + char32_t *utf32_output) { + char32_t *start{utf32_output}; + for (size_t i = 0; i < len; i++) { + *utf32_output++ = uint8_t(data[i]); + } + return utf32_output - start; } } // namespace latin1_to_utf32 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/latin1_to_utf32/latin1_to_utf32.h */ @@ -1867,19 +1903,21 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, char32_t* utf32Outpu #ifndef SIMDUTF_LATIN1_TO_UTF8_H #define SIMDUTF_LATIN1_TO_UTF8_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace latin1_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_byte_like && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_byte_like && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + OutputPtr utf8_output) { // const unsigned char *data = reinterpret_cast(buf); size_t pos = 0; - size_t utf8Pos = 0; + size_t utf8_pos = 0; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -1889,120 +1927,129 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 1000 - // 1000, so it makes sense to concatenate everything - if ((v & 0x8080808080808080) == - 0) { // if NONE of these are set, e.g. all of them are zero, then - // everything is ASCII - size_t finalPos = pos + 16; - while (pos < finalPos) { - utf8Output[utf8Pos++] = char(data[pos]); - pos++; - } - continue; - } + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | + v2}; // We are only interested in these bits: 1000 1000 1000 + // 1000, so it makes sense to concatenate everything + if ((v & 0x8080808080808080) == + 0) { // if NONE of these are set, e.g. all of them are zero, then + // everything is ASCII + size_t final_pos = pos + 16; + while (pos < final_pos) { + utf8_output[utf8_pos++] = char(data[pos]); + pos++; + } + continue; + } } // if (pos + 16 <= len) } // !consteval scope unsigned char byte = data[pos]; if ((byte & 0x80) == 0) { // if ASCII // will generate one UTF-8 bytes - utf8Output[utf8Pos++] = static_cast(byte); + utf8_output[utf8_pos++] = char(byte); pos++; } else { // will generate two UTF-8 bytes - utf8Output[utf8Pos++] = static_cast((byte >> 6) | 0b11000000); - utf8Output[utf8Pos++] = static_cast((byte & 0b111111) | 0b10000000); + utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); + utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); pos++; } } // while - return utf8Pos; -} - -simdutf_really_inline auto convert(const char* buf, size_t len, char* utf8Output) -> size_t { - return convert(reinterpret_cast(buf), len, utf8Output); -} - -inline auto convert_safe(const char* buf, size_t len, char* utf8Output, size_t utf8Len) -> size_t { - const auto* data = reinterpret_cast(buf); - size_t pos = 0; - size_t skipPos = 0; - size_t utf8Pos = 0; - while (pos < len && utf8Pos < utf8Len) { - // try to convert the next block of 16 ASCII bytes - if (pos >= skipPos && pos + 16 <= len && utf8Pos + 16 <= utf8Len) { // if it is safe to read 16 more bytes, - // check that they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 1000 - // 1000, so it makes sense to concatenate everything - if ((v & 0x8080808080808080) == 0) { // if NONE of these are set, e.g. all of them are zero, then - // everything is ASCII - ::memcpy(utf8Output + utf8Pos, buf + pos, 16); - utf8Pos += 16; - pos += 16; - } else { - // At least one of the next 16 bytes are not ASCII, we will process them - // one by one - skipPos = pos + 16; - } - } else { - const auto byte = data[pos]; - if ((byte & 0x80) == 0) { // if ASCII - // will generate one UTF-8 bytes - utf8Output[utf8Pos++] = static_cast(byte); - pos++; - } else if (utf8Pos + 2 <= utf8Len) { - // will generate two UTF-8 bytes - utf8Output[utf8Pos++] = static_cast((byte >> 6) | 0b11000000); - utf8Output[utf8Pos++] = static_cast((byte & 0b111111) | 0b10000000); - pos++; - } else { - break; - } - } + return utf8_pos; +} + +simdutf_really_inline size_t convert(const char *buf, size_t len, + char *utf8_output) { + return convert(reinterpret_cast(buf), len, + utf8_output); +} + +inline size_t convert_safe(const char *buf, size_t len, char *utf8_output, + size_t utf8_len) { + const unsigned char *data = reinterpret_cast(buf); + size_t pos = 0; + size_t skip_pos = 0; + size_t utf8_pos = 0; + while (pos < len && utf8_pos < utf8_len) { + // try to convert the next block of 16 ASCII bytes + if (pos >= skip_pos && pos + 16 <= len && + utf8_pos + 16 <= utf8_len) { // if it is safe to read 16 more bytes, + // check that they are ascii + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | + v2}; // We are only interested in these bits: 1000 1000 1000 + // 1000, so it makes sense to concatenate everything + if ((v & 0x8080808080808080) == + 0) { // if NONE of these are set, e.g. all of them are zero, then + // everything is ASCII + ::memcpy(utf8_output + utf8_pos, buf + pos, 16); + utf8_pos += 16; + pos += 16; + } else { + // At least one of the next 16 bytes are not ASCII, we will process them + // one by one + skip_pos = pos + 16; + } + } else { + const auto byte = data[pos]; + if ((byte & 0x80) == 0) { // if ASCII + // will generate one UTF-8 bytes + utf8_output[utf8_pos++] = char(byte); + pos++; + } else if (utf8_pos + 2 <= utf8_len) { + // will generate two UTF-8 bytes + utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); + utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); + pos++; + } else { + break; + } } - return utf8Pos; + } + return utf8_pos; } template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_byte_like && - simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_byte_like && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert_safe_constexpr(InputPtr data, size_t len, OutputPtr utf8Output, size_t utf8Len) - -> size_t { +simdutf_constexpr23 size_t convert_safe_constexpr(InputPtr data, size_t len, + OutputPtr utf8_output, + size_t utf8_len) { size_t pos = 0; - size_t utf8Pos = 0; - while (pos < len && utf8Pos < utf8Len) { - const unsigned char byte = data[pos]; - if ((byte & 0x80) == 0) { // if ASCII - // will generate one UTF-8 bytes - utf8Output[utf8Pos++] = char(byte); - pos++; - } else if (utf8Pos + 2 <= utf8Len) { - // will generate two UTF-8 bytes - utf8Output[utf8Pos++] = char((byte >> 6) | 0b11000000); - utf8Output[utf8Pos++] = char((byte & 0b111111) | 0b10000000); - pos++; - } else { - break; - } + size_t utf8_pos = 0; + while (pos < len && utf8_pos < utf8_len) { + const unsigned char byte = data[pos]; + if ((byte & 0x80) == 0) { // if ASCII + // will generate one UTF-8 bytes + utf8_output[utf8_pos++] = char(byte); + pos++; + } else if (utf8_pos + 2 <= utf8_len) { + // will generate two UTF-8 bytes + utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); + utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); + pos++; + } else { + break; + } } - return utf8Pos; + return utf8_pos; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 simdutf_warn_unused auto utf8_length_from_latin1(InputPtr input, size_t length) noexcept -> size_t { +simdutf_constexpr23 simdutf_warn_unused size_t +utf8_length_from_latin1(InputPtr input, size_t length) noexcept { size_t answer = length; size_t i = 0; @@ -2010,24 +2057,26 @@ simdutf_constexpr23 simdutf_warn_unused auto utf8_length_from_latin1(InputPtr in if !consteval #endif { - auto pop = [](uint64_t v) -> auto { - return static_cast(((v >> 7) & UINT64_C(0x0101010101010101)) * UINT64_C(0x0101010101010101) >> 56); - }; - for (; i + 32 <= length; i += 32) { - uint64_t v = 0; - memcpy(&v, input + i, 8); - answer += pop(v); - memcpy(&v, input + i + 8, sizeof(v)); - answer += pop(v); - memcpy(&v, input + i + 16, sizeof(v)); - answer += pop(v); - memcpy(&v, input + i + 24, sizeof(v)); - answer += pop(v); - } + auto pop = [](uint64_t v) { + return (size_t)(((v >> 7) & UINT64_C(0x0101010101010101)) * + UINT64_C(0x0101010101010101) >> + 56); + }; + for (; i + 32 <= length; i += 32) { + uint64_t v; + memcpy(&v, input + i, 8); + answer += pop(v); + memcpy(&v, input + i + 8, sizeof(v)); + answer += pop(v); + memcpy(&v, input + i + 16, sizeof(v)); + answer += pop(v); + memcpy(&v, input + i + 24, sizeof(v)); + answer += pop(v); + } for (; i + 8 <= length; i += 8) { - uint64_t v = 0; - memcpy(&v, input + i, sizeof(v)); - answer += pop(v); + uint64_t v; + memcpy(&v, input + i, sizeof(v)); + answer += pop(v); } } // !consteval scope for (; i + 1 <= length; i += 1) { @@ -2038,7 +2087,8 @@ simdutf_constexpr23 simdutf_warn_unused auto utf8_length_from_latin1(InputPtr in } // namespace latin1_to_utf8 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/latin1_to_utf8/latin1_to_utf8.h */ @@ -2046,183 +2096,199 @@ simdutf_constexpr23 simdutf_warn_unused auto utf8_length_from_latin1(InputPtr in #ifndef SIMDUTF_UTF16_H #define SIMDUTF_UTF16_H -namespace simdutf::scalar::utf16 { +namespace simdutf { +namespace scalar { +namespace utf16 { template -simdutf_warn_unused simdutf_constexpr23 auto validate_as_ascii(const char16_t* data, size_t len) noexcept -> bool { - for (size_t pos = 0; pos < len; pos++) { - char16_t word = scalar::utf16::swap_if_needed(data[pos]); - if (word >= 0x80) { - return false; - } +simdutf_warn_unused simdutf_constexpr23 bool +validate_as_ascii(const char16_t *data, size_t len) noexcept { + for (size_t pos = 0; pos < len; pos++) { + char16_t word = scalar::utf16::swap_if_needed(data[pos]); + if (word >= 0x80) { + return false; } - return true; + } + return true; } template -simdutf_warn_unused simdutf_constexpr23 auto validate(const char16_t* data, size_t len) noexcept -> bool { - uint64_t pos = 0; - while (pos < len) { - char16_t word = scalar::utf16::swap_if_needed(data[pos]); - if ((word & 0xF800) == 0xD800) { - if (pos + 1 >= len) { - return false; - } - auto diff = static_cast(word - 0xD800); - if (diff > 0x3FF) { - return false; - } - char16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - auto diff2 = static_cast(nextWord - 0xDC00); - if (diff2 > 0x3FF) { - return false; - } - pos += 2; - } else { - pos++; - } +inline simdutf_warn_unused simdutf_constexpr23 bool +validate(const char16_t *data, size_t len) noexcept { + uint64_t pos = 0; + while (pos < len) { + char16_t word = scalar::utf16::swap_if_needed(data[pos]); + if ((word & 0xF800) == 0xD800) { + if (pos + 1 >= len) { + return false; + } + char16_t diff = char16_t(word - 0xD800); + if (diff > 0x3FF) { + return false; + } + char16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + char16_t diff2 = char16_t(next_word - 0xDC00); + if (diff2 > 0x3FF) { + return false; + } + pos += 2; + } else { + pos++; } - return true; + } + return true; } template -simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(const char16_t* data, size_t len) noexcept -> result { - size_t pos = 0; - while (pos < len) { - char16_t word = scalar::utf16::swap_if_needed(data[pos]); - if ((word & 0xF800) == 0xD800) { - if (pos + 1 >= len) { - return {error_code::SURROGATE, pos}; - } - auto diff = static_cast(word - 0xD800); - if (diff > 0x3FF) { - return {error_code::SURROGATE, pos}; - } - char16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - char16_t diff2 = static_cast(nextWord - 0xDC00); - if (diff2 > 0x3FF) { - return {error_code::SURROGATE, pos}; - } - pos += 2; - } else { - pos++; - } +inline simdutf_warn_unused simdutf_constexpr23 result +validate_with_errors(const char16_t *data, size_t len) noexcept { + size_t pos = 0; + while (pos < len) { + char16_t word = scalar::utf16::swap_if_needed(data[pos]); + if ((word & 0xF800) == 0xD800) { + if (pos + 1 >= len) { + return result(error_code::SURROGATE, pos); + } + char16_t diff = char16_t(word - 0xD800); + if (diff > 0x3FF) { + return result(error_code::SURROGATE, pos); + } + char16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + char16_t diff2 = uint16_t(next_word - 0xDC00); + if (diff2 > 0x3FF) { + return result(error_code::SURROGATE, pos); + } + pos += 2; + } else { + pos++; } - return {error_code::SUCCESS, pos}; + } + return result(error_code::SUCCESS, pos); } -template simdutf_constexpr23 auto count_code_points(const char16_t* p, size_t len) -> size_t { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - char16_t word = scalar::utf16::swap_if_needed(p[i]); - counter += ((word & 0xFC00) != 0xDC00); - } - return counter; +template +simdutf_constexpr23 size_t count_code_points(const char16_t *p, size_t len) { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + char16_t word = scalar::utf16::swap_if_needed(p[i]); + counter += ((word & 0xFC00) != 0xDC00); + } + return counter; } template -simdutf_constexpr23 auto utf8_length_from_utf16(const char16_t* p, size_t len) -> size_t { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - char16_t word = scalar::utf16::swap_if_needed(p[i]); - counter++; // ASCII - counter += static_cast(word > 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes - counter += static_cast((word > 0x7FF && word <= 0xD7FF) || (word >= 0xE000)); // three-byte - } - return counter; +simdutf_constexpr23 size_t utf8_length_from_utf16(const char16_t *p, + size_t len) { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + char16_t word = scalar::utf16::swap_if_needed(p[i]); + counter++; // ASCII + counter += static_cast( + word > + 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes + counter += static_cast((word > 0x7FF && word <= 0xD7FF) || + (word >= 0xE000)); // three-byte + } + return counter; } template -simdutf_constexpr23 auto utf32_length_from_utf16(const char16_t* p, size_t len) -> size_t { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - char16_t word = scalar::utf16::swap_if_needed(p[i]); - counter += ((word & 0xFC00) != 0xDC00); - } - return counter; +simdutf_constexpr23 size_t utf32_length_from_utf16(const char16_t *p, + size_t len) { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + char16_t word = scalar::utf16::swap_if_needed(p[i]); + counter += ((word & 0xFC00) != 0xDC00); + } + return counter; } simdutf_really_inline simdutf_constexpr23 void change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) { for (size_t i = 0; i < size; i++) { - *output++ = static_cast(input[i] >> 8 | input[i] << 8); + *output++ = char16_t(input[i] >> 8 | input[i] << 8); } } template -simdutf_warn_unused simdutf_constexpr23 auto trim_partial_utf16(const char16_t* input, size_t length) -> size_t { - if (length == 0) { - return 0; - } - auto lastWord = static_cast(input[length - 1]); - lastWord = scalar::utf16::swap_if_needed(lastWord); - length -= ((lastWord & 0xFC00) == 0xD800); - return length; +simdutf_warn_unused simdutf_constexpr23 size_t +trim_partial_utf16(const char16_t *input, size_t length) { + if (length == 0) { + return 0; + } + uint16_t last_word = uint16_t(input[length - 1]); + last_word = scalar::utf16::swap_if_needed(last_word); + length -= ((last_word & 0xFC00) == 0xD800); + return length; } -template constexpr auto is_high_surrogate(char16_t c) -> bool { - c = scalar::utf16::swap_if_needed(c); - return (0xd800 <= c && c <= 0xdbff); +template constexpr bool is_high_surrogate(char16_t c) { + c = scalar::utf16::swap_if_needed(c); + return (0xd800 <= c && c <= 0xdbff); } -template constexpr auto is_low_surrogate(char16_t c) -> bool { - c = scalar::utf16::swap_if_needed(c); - return (0xdc00 <= c && c <= 0xdfff); +template constexpr bool is_low_surrogate(char16_t c) { + c = scalar::utf16::swap_if_needed(c); + return (0xdc00 <= c && c <= 0xdfff); } -simdutf_really_inline constexpr auto high_surrogate(char16_t c) -> bool { - return (0xd800 <= c && c <= 0xdbff); +simdutf_really_inline constexpr bool high_surrogate(char16_t c) { + return (0xd800 <= c && c <= 0xdbff); } -simdutf_really_inline constexpr auto low_surrogate(char16_t c) -> bool { - return (0xdc00 <= c && c <= 0xdfff); +simdutf_really_inline constexpr bool low_surrogate(char16_t c) { + return (0xdc00 <= c && c <= 0xdfff); } template -simdutf_constexpr23 auto utf8_length_from_utf16_with_replacement(const char16_t* p, size_t len) -> result { - bool any_surrogates = false; - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - if (is_high_surrogate(p[i])) { - any_surrogates = true; - // surrogate pair - if (i + 1 < len && is_low_surrogate(p[i + 1])) { - counter += 4; - i++; // skip low surrogate - } else { - counter += 3; // unpaired high surrogate replaced by U+FFFD - } - continue; - } - if (is_low_surrogate(p[i])) { - any_surrogates = true; - counter += 3; // unpaired low surrogate replaced by U+FFFD - continue; - } - char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; - counter++; // at least 1 byte - counter += static_cast(word > 0x7F); // non-ASCII is at least 2 bytes - counter += static_cast(word > 0x7FF); // three-byte +simdutf_constexpr23 result +utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) { + bool any_surrogates = false; + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + if (is_high_surrogate(p[i])) { + any_surrogates = true; + // surrogate pair + if (i + 1 < len && is_low_surrogate(p[i + 1])) { + counter += 4; + i++; // skip low surrogate + } else { + counter += 3; // unpaired high surrogate replaced by U+FFFD + } + continue; + } else if (is_low_surrogate(p[i])) { + any_surrogates = true; + counter += 3; // unpaired low surrogate replaced by U+FFFD + continue; } - return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, counter}; + char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; + counter++; // at least 1 byte + counter += + static_cast(word > 0x7F); // non-ASCII is at least 2 bytes + counter += static_cast(word > 0x7FF); // three-byte + } + return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, + counter}; } // variable templates are a C++14 extension -template constexpr auto replacement() -> char16_t { - return !match_system(big_endian) ? scalar::u16_swap_bytes(0xfffd) : 0xfffd; +template constexpr char16_t replacement() { + return !match_system(big_endian) ? scalar::u16_swap_bytes(0xfffd) : 0xfffd; } template simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, char16_t *output) { const char16_t replacement = utf16::replacement(); - bool high_surrogate_prev = false; - bool high_surrogate; - bool low_surrogate; + bool high_surrogate_prev = false, high_surrogate, low_surrogate; size_t i = 0; for (; i < len; i++) { char16_t c = input[i]; @@ -2246,7 +2312,9 @@ simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, } } -} // namespace simdutf::scalar::utf16 +} // namespace utf16 +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf16.h */ @@ -2256,47 +2324,52 @@ simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, #include // for std::memcpy -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf16_to_latin1 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf16 && simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf16 && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr latinOutput) -> size_t { +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + OutputPtr latin_output) { if (len == 0) { return 0; } size_t pos = 0; - const auto latinOutputStart = latinOutput; + const auto latin_output_start = latin_output; uint16_t word = 0; - uint16_t tooLarge = 0; + uint16_t too_large = 0; while (pos < len) { word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - tooLarge |= word; - *latinOutput++ = static_cast(word & 0xFF); + too_large |= word; + *latin_output++ = char(word & 0xFF); pos++; } - if ((tooLarge & 0xFF00) != 0) { - return 0; + if ((too_large & 0xFF00) != 0) { + return 0; } - return latinOutput - latinOutputStart; + return latin_output - latin_output_start; } template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf16 && simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf16 && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPtr latinOutput) -> result { +simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, + OutputPtr latin_output) { if (len == 0) { - return {error_code::SUCCESS, 0}; + return result(error_code::SUCCESS, 0); } size_t pos = 0; - auto start = latinOutput; - uint16_t word = 0; + auto start = latin_output; + uint16_t word; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -2305,18 +2378,15 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPt { if (pos + 16 <= len) { // if it is safe to read 32 more bytes, check that // they are Latin1 - uint64_t v1; - uint64_t v2; - uint64_t v3; - uint64_t v4; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - ::memcpy(&v2, data + pos + 4, sizeof(uint64_t)); - ::memcpy(&v3, data + pos + 8, sizeof(uint64_t)); - ::memcpy(&v4, data + pos + 12, sizeof(uint64_t)); - - if constexpr (!match_system(big_endian)) { - v1 = (v1 >> 8) | (v1 << (64 - 8)); - } + uint64_t v1, v2, v3, v4; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + ::memcpy(&v2, data + pos + 4, sizeof(uint64_t)); + ::memcpy(&v3, data + pos + 8, sizeof(uint64_t)); + ::memcpy(&v4, data + pos + 12, sizeof(uint64_t)); + + if constexpr (!match_system(big_endian)) { + v1 = (v1 >> 8) | (v1 << (64 - 8)); + } if constexpr (!match_system(big_endian)) { v2 = (v2 >> 8) | (v2 << (64 - 8)); } @@ -2328,11 +2398,13 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPt } if (((v1 | v2 | v3 | v4) & 0xFF00FF00FF00FF00) == 0) { - size_t finalPos = pos + 16; - while (pos < finalPos) { - *latinOutput++ = !match_system(big_endian) ? char(u16_swap_bytes(data[pos])) : char(data[pos]); - pos++; - } + size_t final_pos = pos + 16; + while (pos < final_pos) { + *latin_output++ = !match_system(big_endian) + ? char(u16_swap_bytes(data[pos])) + : char(data[pos]); + pos++; + } continue; } } @@ -2340,18 +2412,19 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPt word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF00) == 0) { - *latinOutput++ = static_cast(word & 0xFF); - pos++; + *latin_output++ = char(word & 0xFF); + pos++; } else { - return {error_code::TOO_LARGE, pos}; + return result(error_code::TOO_LARGE, pos); } } - return result(error_code::SUCCESS, latinOutput - start); + return result(error_code::SUCCESS, latin_output - start); } } // namespace utf16_to_latin1 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf16_to_latin1/utf16_to_latin1.h */ @@ -2359,34 +2432,41 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPt #ifndef SIMDUTF_VALID_UTF16_TO_LATIN1_H #define SIMDUTF_VALID_UTF16_TO_LATIN1_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf16_to_latin1 { template -simdutf_constexpr23 inline auto convert_valid_impl(InputIterator data, size_t len, OutputIterator latinOutput) - -> size_t { - static_assert(std::is_same_v, uint16_t>, "must decay to uint16_t"); - size_t pos = 0; - const auto start = latinOutput; - uint16_t word = 0; - - while (pos < len) { - word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - *latinOutput++ = static_cast(word); - pos++; - } +simdutf_constexpr23 inline size_t +convert_valid_impl(InputIterator data, size_t len, + OutputIterator latin_output) { + static_assert( + std::is_same::type, uint16_t>::value, + "must decay to uint16_t"); + size_t pos = 0; + const auto start = latin_output; + uint16_t word = 0; + + while (pos < len) { + word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; + *latin_output++ = char(word); + pos++; + } - return latinOutput - start; + return latin_output - start; } template -simdutf_really_inline auto convert_valid(const char16_t* buf, size_t len, char* latinOutput) -> size_t { - return convert_valid_impl(reinterpret_cast(buf), len, latinOutput); +simdutf_really_inline size_t convert_valid(const char16_t *buf, size_t len, + char *latin_output) { + return convert_valid_impl(reinterpret_cast(buf), + len, latin_output); } } // namespace utf16_to_latin1 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf16_to_latin1/valid_utf16_to_latin1.h */ @@ -2394,77 +2474,87 @@ simdutf_really_inline auto convert_valid(const char16_t* buf, size_t len, char* #ifndef SIMDUTF_UTF16_TO_UTF32_H #define SIMDUTF_UTF16_TO_UTF32_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf16_to_utf32 { template -simdutf_constexpr23 auto convert(const char16_t* data, size_t len, char32_t* utf32Output) -> size_t { - size_t pos = 0; - char32_t* start{utf32Output}; - while (pos < len) { - uint16_t word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - if ((word & 0xF800) != 0xD800) { - // No surrogate pair, extend 16-bit word to 32-bit word - *utf32Output++ = static_cast(word); - pos++; - } else { - // must be a surrogate pair - auto diff = static_cast(word - 0xD800); - if (diff > 0x3FF) { - return 0; - } - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - auto diff2 = static_cast(nextWord - 0xDC00); - if (diff2 > 0x3FF) { - return 0; - } - uint32_t value = (diff << 10) + diff2 + 0x10000; - *utf32Output++ = static_cast(value); - pos += 2; - } +simdutf_constexpr23 size_t convert(const char16_t *data, size_t len, + char32_t *utf32_output) { + size_t pos = 0; + char32_t *start{utf32_output}; + while (pos < len) { + uint16_t word = + !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; + if ((word & 0xF800) != 0xD800) { + // No surrogate pair, extend 16-bit word to 32-bit word + *utf32_output++ = char32_t(word); + pos++; + } else { + // must be a surrogate pair + uint16_t diff = uint16_t(word - 0xD800); + if (diff > 0x3FF) { + return 0; + } + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + uint16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + uint16_t diff2 = uint16_t(next_word - 0xDC00); + if (diff2 > 0x3FF) { + return 0; + } + uint32_t value = (diff << 10) + diff2 + 0x10000; + *utf32_output++ = char32_t(value); + pos += 2; } - return utf32Output - start; + } + return utf32_output - start; } template -simdutf_constexpr23 auto convert_with_errors(const char16_t* data, size_t len, char32_t* utf32Output) -> result { - size_t pos = 0; - char32_t* start{utf32Output}; - while (pos < len) { - uint16_t word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - if ((word & 0xF800) != 0xD800) { - // No surrogate pair, extend 16-bit word to 32-bit word - *utf32Output++ = static_cast(word); - pos++; - } else { - // must be a surrogate pair - auto diff = static_cast(word - 0xD800); - if (diff > 0x3FF) { - return {error_code::SURROGATE, pos}; - } - if (pos + 1 >= len) { - return {error_code::SURROGATE, pos}; - } // minimal bound checking - uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - auto diff2 = static_cast(nextWord - 0xDC00); - if (diff2 > 0x3FF) { - return {error_code::SURROGATE, pos}; - } - uint32_t value = (diff << 10) + diff2 + 0x10000; - *utf32Output++ = static_cast(value); - pos += 2; - } +simdutf_constexpr23 result convert_with_errors(const char16_t *data, size_t len, + char32_t *utf32_output) { + size_t pos = 0; + char32_t *start{utf32_output}; + while (pos < len) { + uint16_t word = + !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; + if ((word & 0xF800) != 0xD800) { + // No surrogate pair, extend 16-bit word to 32-bit word + *utf32_output++ = char32_t(word); + pos++; + } else { + // must be a surrogate pair + uint16_t diff = uint16_t(word - 0xD800); + if (diff > 0x3FF) { + return result(error_code::SURROGATE, pos); + } + if (pos + 1 >= len) { + return result(error_code::SURROGATE, pos); + } // minimal bound checking + uint16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + uint16_t diff2 = uint16_t(next_word - 0xDC00); + if (diff2 > 0x3FF) { + return result(error_code::SURROGATE, pos); + } + uint32_t value = (diff << 10) + diff2 + 0x10000; + *utf32_output++ = char32_t(value); + pos += 2; } - return {error_code::SUCCESS, utf32Output - start}; + } + return result(error_code::SUCCESS, utf32_output - start); } } // namespace utf16_to_utf32 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf16_to_utf32/utf16_to_utf32.h */ @@ -2472,39 +2562,45 @@ simdutf_constexpr23 auto convert_with_errors(const char16_t* data, size_t len, c #ifndef SIMDUTF_VALID_UTF16_TO_UTF32_H #define SIMDUTF_VALID_UTF16_TO_UTF32_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf16_to_utf32 { template -simdutf_constexpr23 auto convert_valid(const char16_t* data, size_t len, char32_t* utf32Output) -> size_t { - size_t pos = 0; - char32_t* start{utf32Output}; - while (pos < len) { - uint16_t word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; - if ((word & 0xF800) != 0xD800) { - // No surrogate pair, extend 16-bit word to 32-bit word - *utf32Output++ = static_cast(word); - pos++; - } else { - // must be a surrogate pair - auto diff = static_cast(word - 0xD800); - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - auto diff2 = static_cast(nextWord - 0xDC00); - uint32_t value = (diff << 10) + diff2 + 0x10000; - *utf32Output++ = static_cast(value); - pos += 2; - } +simdutf_constexpr23 size_t convert_valid(const char16_t *data, size_t len, + char32_t *utf32_output) { + size_t pos = 0; + char32_t *start{utf32_output}; + while (pos < len) { + uint16_t word = + !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; + if ((word & 0xF800) != 0xD800) { + // No surrogate pair, extend 16-bit word to 32-bit word + *utf32_output++ = char32_t(word); + pos++; + } else { + // must be a surrogate pair + uint16_t diff = uint16_t(word - 0xD800); + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + uint16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + uint16_t diff2 = uint16_t(next_word - 0xDC00); + uint32_t value = (diff << 10) + diff2 + 0x10000; + *utf32_output++ = char32_t(value); + pos += 2; } - return utf32Output - start; + } + return utf32_output - start; } } // namespace utf16_to_utf32 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf16_to_utf32/valid_utf16_to_utf32.h */ @@ -2512,18 +2608,20 @@ simdutf_constexpr23 auto convert_valid(const char16_t* data, size_t len, char32_ #ifndef SIMDUTF_UTF16_TO_UTF8_H #define SIMDUTF_UTF16_TO_UTF8_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf16_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_utf16 + requires simdutf::detail::indexes_into_utf16 // FIXME constrain output as well #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + OutputPtr utf8_output) { size_t pos = 0; - const auto start = utf8Output; + const auto start = utf8_output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -2532,17 +2630,19 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output // try to convert the next block of 8 bytes if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if constexpr (!match_system(big_endian)) { - v = (v >> 8) | (v << (64 - 8)); - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if constexpr (!match_system(big_endian)) { + v = (v >> 8) | (v << (64 - 8)); + } if ((v & 0xFF80FF80FF80FF80) == 0) { - size_t finalPos = pos + 4; - while (pos < finalPos) { - *utf8Output++ = !match_system(big_endian) ? char(u16_swap_bytes(data[pos])) : char(data[pos]); - pos++; - } + size_t final_pos = pos + 4; + while (pos < final_pos) { + *utf8_output++ = !match_system(big_endian) + ? char(u16_swap_bytes(data[pos])) + : char(data[pos]); + pos++; + } continue; } } @@ -2551,61 +2651,66 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF80) == 0) { // will generate one UTF-8 bytes - *utf8Output++ = static_cast(word); + *utf8_output++ = char(word); pos++; } else if ((word & 0xF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 6) | 0b11000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xF800) != 0xD800) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 12) | 0b11100000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else { // must be a surrogate pair if (pos + 1 >= len) { return 0; } - auto diff = static_cast(word - 0xD800); + uint16_t diff = uint16_t(word - 0xD800); if (diff > 0x3FF) { return 0; } - uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - auto diff2 = static_cast(nextWord - 0xDC00); + uint16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + uint16_t diff2 = uint16_t(next_word - 0xDC00); if (diff2 > 0x3FF) { return 0; } uint32_t value = (diff << 10) + diff2 + 0x10000; // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - *utf8Output++ = static_cast((value >> 18) | 0b11110000); - *utf8Output++ = static_cast(((value >> 12) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast(((value >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((value & 0b111111) | 0b10000000); + *utf8_output++ = char((value >> 18) | 0b11110000); + *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((value & 0b111111) | 0b10000000); pos += 2; } } - return utf8Output - start; + return utf8_output - start; } -template +template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf16 && simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf16 && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPtr utf8Output, size_t utf8Len = 0) - -> full_result { - if (check_output && utf8Len == 0) { - return {error_code::OUTPUT_BUFFER_TOO_SMALL, 0, 0}; - } +simdutf_constexpr23 full_result convert_with_errors(InputPtr data, size_t len, + OutputPtr utf8_output, + size_t utf8_len = 0) { + if (check_output && utf8_len == 0) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, 0, 0); + } size_t pos = 0; - auto start = utf8Output; - auto end = utf8Output + utf8Len; + auto start = utf8_output; + auto end = utf8_output + utf8_len; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -2615,20 +2720,22 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPt // try to convert the next block of 8 bytes if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if constexpr (!match_system(big_endian)) { - v = (v >> 8) | (v << (64 - 8)); - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if constexpr (!match_system(big_endian)) + v = (v >> 8) | (v << (64 - 8)); if ((v & 0xFF80FF80FF80FF80) == 0) { - size_t finalPos = pos + 4; - while (pos < finalPos) { - if (check_output && size_t(end - utf8Output) < 1) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); - } - *utf8Output++ = !match_system(big_endian) ? char(u16_swap_bytes(data[pos])) : char(data[pos]); - pos++; + size_t final_pos = pos + 4; + while (pos < final_pos) { + if (check_output && size_t(end - utf8_output) < 1) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, + utf8_output - start); } + *utf8_output++ = !match_system(big_endian) + ? char(u16_swap_bytes(data[pos])) + : char(data[pos]); + pos++; + } continue; } } @@ -2638,71 +2745,81 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPt !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF80) == 0) { // will generate one UTF-8 bytes - if (check_output && size_t(end - utf8Output) < 1) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); + if (check_output && size_t(end - utf8_output) < 1) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, + utf8_output - start); } - *utf8Output++ = static_cast(word); + *utf8_output++ = char(word); pos++; } else if ((word & 0xF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - if (check_output && size_t(end - utf8Output) < 2) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); + if (check_output && size_t(end - utf8_output) < 2) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, + utf8_output - start); } - *utf8Output++ = static_cast((word >> 6) | 0b11000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xF800) != 0xD800) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - if (check_output && size_t(end - utf8Output) < 3) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); + if (check_output && size_t(end - utf8_output) < 3) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, + utf8_output - start); } - *utf8Output++ = static_cast((word >> 12) | 0b11100000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else { - if (check_output && size_t(end - utf8Output) < 4) { - return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, utf8Output - start); - } + + if (check_output && size_t(end - utf8_output) < 4) { + return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, + utf8_output - start); + } // must be a surrogate pair if (pos + 1 >= len) { - return full_result(error_code::SURROGATE, pos, utf8Output - start); + return full_result(error_code::SURROGATE, pos, utf8_output - start); } - auto diff = static_cast(word - 0xD800); + uint16_t diff = uint16_t(word - 0xD800); if (diff > 0x3FF) { - return full_result(error_code::SURROGATE, pos, utf8Output - start); + return full_result(error_code::SURROGATE, pos, utf8_output - start); } - uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - auto diff2 = static_cast(nextWord - 0xDC00); + uint16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + uint16_t diff2 = uint16_t(next_word - 0xDC00); if (diff2 > 0x3FF) { - return full_result(error_code::SURROGATE, pos, utf8Output - start); + return full_result(error_code::SURROGATE, pos, utf8_output - start); } uint32_t value = (diff << 10) + diff2 + 0x10000; // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - *utf8Output++ = static_cast((value >> 18) | 0b11110000); - *utf8Output++ = static_cast(((value >> 12) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast(((value >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((value & 0b111111) | 0b10000000); + *utf8_output++ = char((value >> 18) | 0b11110000); + *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((value & 0b111111) | 0b10000000); pos += 2; } } - return full_result(error_code::SUCCESS, pos, utf8Output - start); + return full_result(error_code::SUCCESS, pos, utf8_output - start); } template -inline auto simple_convert_with_errors(const char16_t* buf, size_t len, char* utf8Output) -> result { - return convert_with_errors(buf, len, utf8Output, 0); +inline result simple_convert_with_errors(const char16_t *buf, size_t len, + char *utf8_output) { + return convert_with_errors(buf, len, utf8_output, 0); } template -simdutf_constexpr23 auto convert_with_replacement(const char16_t* data, size_t len, char* utf8Output) -> size_t { - size_t pos = 0; - char* start = utf8Output; - while (pos < len) { +simdutf_constexpr23 size_t convert_with_replacement(const char16_t *data, + size_t len, + char *utf8_output) { + size_t pos = 0; + char *start = utf8_output; + while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval #endif @@ -2710,18 +2827,19 @@ simdutf_constexpr23 auto convert_with_replacement(const char16_t* data, size_t l // try to convert the next block of 8 bytes if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if constexpr (!match_system(big_endian)) { - v = (v >> 8) | (v << (64 - 8)); - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if constexpr (!match_system(big_endian)) { + v = (v >> 8) | (v << (64 - 8)); + } if ((v & 0xFF80FF80FF80FF80) == 0) { - size_t finalPos = pos + 4; - while (pos < finalPos) { - *utf8Output++ = !match_system(big_endian) ? static_cast(u16_swap_bytes(data[pos])) - : static_cast(data[pos]); - pos++; - } + size_t final_pos = pos + 4; + while (pos < final_pos) { + *utf8_output++ = !match_system(big_endian) + ? char(u16_swap_bytes(data[pos])) + : char(data[pos]); + pos++; + } continue; } } @@ -2730,53 +2848,56 @@ simdutf_constexpr23 auto convert_with_replacement(const char16_t* data, size_t l !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF80) == 0) { // will generate one UTF-8 bytes - *utf8Output++ = static_cast(word); + *utf8_output++ = char(word); pos++; } else if ((word & 0xF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 6) | 0b11000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xF800) != 0xD800) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 12) | 0b11100000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else { // surrogate range - auto diff = static_cast(word - 0xD800); + uint16_t diff = uint16_t(word - 0xD800); if (diff <= 0x3FF && pos + 1 < len) { // high surrogate, check for valid pair - uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - auto diff2 = static_cast(nextWord - 0xDC00); + uint16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + uint16_t diff2 = uint16_t(next_word - 0xDC00); if (diff2 <= 0x3FF) { // valid surrogate pair uint32_t value = (diff << 10) + diff2 + 0x10000; // will generate four UTF-8 bytes - *utf8Output++ = static_cast((value >> 18) | 0b11110000); - *utf8Output++ = static_cast(((value >> 12) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast(((value >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((value & 0b111111) | 0b10000000); + *utf8_output++ = char((value >> 18) | 0b11110000); + *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((value & 0b111111) | 0b10000000); pos += 2; continue; } } // unpaired surrogate: replace with U+FFFD (0xEF 0xBF 0xBD) - *utf8Output++ = static_cast(0xef); - *utf8Output++ = static_cast(0xbf); - *utf8Output++ = static_cast(0xbd); + *utf8_output++ = char(0xef); + *utf8_output++ = char(0xbf); + *utf8_output++ = char(0xbd); pos++; } } - return utf8Output - start; + return utf8_output - start; } } // namespace utf16_to_utf8 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf16_to_utf8/utf16_to_utf8.h */ @@ -2784,17 +2905,20 @@ simdutf_constexpr23 auto convert_with_replacement(const char16_t* data, size_t l #ifndef SIMDUTF_VALID_UTF16_TO_UTF8_H #define SIMDUTF_VALID_UTF16_TO_UTF8_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf16_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf16 && simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf16 && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { +simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, + OutputPtr utf8_output) { size_t pos = 0; - auto start = utf8Output; + auto start = utf8_output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -2803,17 +2927,19 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8 // try to convert the next block of 4 ASCII characters if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if constexpr (!match_system(big_endian)) { - v = (v >> 8) | (v << (64 - 8)); - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if constexpr (!match_system(big_endian)) { + v = (v >> 8) | (v << (64 - 8)); + } if ((v & 0xFF80FF80FF80FF80) == 0) { - size_t finalPos = pos + 4; - while (pos < finalPos) { - *utf8Output++ = !match_system(big_endian) ? char(u16_swap_bytes(data[pos])) : char(data[pos]); - pos++; - } + size_t final_pos = pos + 4; + while (pos < final_pos) { + *utf8_output++ = !match_system(big_endian) + ? char(u16_swap_bytes(data[pos])) + : char(data[pos]); + pos++; + } continue; } } @@ -2823,45 +2949,48 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8 !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; if ((word & 0xFF80) == 0) { // will generate one UTF-8 bytes - *utf8Output++ = static_cast(word); + *utf8_output++ = char(word); pos++; } else if ((word & 0xF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 6) | 0b11000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xF800) != 0xD800) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 12) | 0b11100000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else { // must be a surrogate pair - auto diff = static_cast(word - 0xD800); + uint16_t diff = uint16_t(word - 0xD800); if (pos + 1 >= len) { return 0; } // minimal bound checking - uint16_t nextWord = !match_system(big_endian) ? u16_swap_bytes(data[pos + 1]) : data[pos + 1]; - auto diff2 = static_cast(nextWord - 0xDC00); + uint16_t next_word = !match_system(big_endian) + ? u16_swap_bytes(data[pos + 1]) + : data[pos + 1]; + uint16_t diff2 = uint16_t(next_word - 0xDC00); uint32_t value = (diff << 10) + diff2 + 0x10000; // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - *utf8Output++ = static_cast((value >> 18) | 0b11110000); - *utf8Output++ = static_cast(((value >> 12) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast(((value >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((value & 0b111111) | 0b10000000); + *utf8_output++ = char((value >> 18) | 0b11110000); + *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((value & 0b111111) | 0b10000000); pos += 2; } } - return utf8Output - start; + return utf8_output - start; } } // namespace utf16_to_utf8 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf16_to_utf8/valid_utf16_to_utf8.h */ @@ -2869,13 +2998,16 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8 #ifndef SIMDUTF_UTF32_H #define SIMDUTF_UTF32_H -namespace simdutf::scalar::utf32 { +namespace simdutf { +namespace scalar { +namespace utf32 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_uint32 + requires simdutf::detail::indexes_into_uint32 #endif -simdutf_warn_unused simdutf_constexpr23 auto validate(InputPtr data, size_t len) noexcept -> bool { +simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, + size_t len) noexcept { uint64_t pos = 0; for (; pos < len; pos++) { uint32_t word = data[pos]; @@ -2886,57 +3018,63 @@ simdutf_warn_unused simdutf_constexpr23 auto validate(InputPtr data, size_t len) return true; } -simdutf_warn_unused simdutf_really_inline auto validate(const char32_t* buf, size_t len) noexcept -> bool { - return validate(reinterpret_cast(buf), len); +simdutf_warn_unused simdutf_really_inline bool validate(const char32_t *buf, + size_t len) noexcept { + return validate(reinterpret_cast(buf), len); } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_uint32 + requires simdutf::detail::indexes_into_uint32 #endif -simdutf_warn_unused simdutf_constexpr23 auto validate_with_errors(InputPtr data, size_t len) noexcept -> result { +simdutf_warn_unused simdutf_constexpr23 result +validate_with_errors(InputPtr data, size_t len) noexcept { size_t pos = 0; for (; pos < len; pos++) { uint32_t word = data[pos]; if (word > 0x10FFFF) { - return {error_code::TOO_LARGE, pos}; + return result(error_code::TOO_LARGE, pos); } if (word >= 0xD800 && word <= 0xDFFF) { - return {error_code::SURROGATE, pos}; + return result(error_code::SURROGATE, pos); } } - return {error_code::SUCCESS, pos}; + return result(error_code::SUCCESS, pos); } -simdutf_warn_unused simdutf_really_inline auto validate_with_errors(const char32_t* buf, size_t len) noexcept - -> result { - return validate_with_errors(reinterpret_cast(buf), len); +simdutf_warn_unused simdutf_really_inline result +validate_with_errors(const char32_t *buf, size_t len) noexcept { + return validate_with_errors(reinterpret_cast(buf), len); } -simdutf_constexpr23 auto utf8_length_from_utf32(const char32_t* p, size_t len) -> size_t { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - // credit: @ttsugriy for the vectorizable approach - counter++; // ASCII - counter += static_cast(p[i] > 0x7F); // two-byte - counter += static_cast(p[i] > 0x7FF); // three-byte - counter += static_cast(p[i] > 0xFFFF); // four-bytes - } - return counter; +inline simdutf_constexpr23 size_t utf8_length_from_utf32(const char32_t *p, + size_t len) { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + // credit: @ttsugriy for the vectorizable approach + counter++; // ASCII + counter += static_cast(p[i] > 0x7F); // two-byte + counter += static_cast(p[i] > 0x7FF); // three-byte + counter += static_cast(p[i] > 0xFFFF); // four-bytes + } + return counter; } -simdutf_warn_unused simdutf_constexpr23 auto utf16_length_from_utf32(const char32_t* p, size_t len) -> size_t { - // We are not BOM aware. - size_t counter{0}; - for (size_t i = 0; i < len; i++) { - counter++; // non-surrogate word - counter += static_cast(p[i] > 0xFFFF); // surrogate pair - } - return counter; +inline simdutf_warn_unused simdutf_constexpr23 size_t +utf16_length_from_utf32(const char32_t *p, size_t len) { + // We are not BOM aware. + size_t counter{0}; + for (size_t i = 0; i < len; i++) { + counter++; // non-surrogate word + counter += static_cast(p[i] > 0xFFFF); // surrogate pair + } + return counter; } -} // namespace simdutf::scalar::utf32 +} // namespace utf32 +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf32.h */ @@ -2944,63 +3082,69 @@ simdutf_warn_unused simdutf_constexpr23 auto utf16_length_from_utf32(const char3 #ifndef SIMDUTF_UTF32_TO_LATIN1_H #define SIMDUTF_UTF32_TO_LATIN1_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf32_to_latin1 { -simdutf_constexpr23 auto convert(const char32_t* data, size_t len, char* latin1Output) -> size_t { - char* start = latin1Output; - uint32_t utf32Char = 0; - size_t pos = 0; - uint32_t tooLarge = 0; +inline simdutf_constexpr23 size_t convert(const char32_t *data, size_t len, + char *latin1_output) { + char *start = latin1_output; + uint32_t utf32_char; + size_t pos = 0; + uint32_t too_large = 0; - while (pos < len) { - utf32Char = static_cast(data[pos]); - tooLarge |= utf32Char; - *latin1Output++ = static_cast(utf32Char & 0xFF); - pos++; - } - if ((tooLarge & 0xFFFFFF00) != 0) { - return 0; - } - return latin1Output - start; + while (pos < len) { + utf32_char = (uint32_t)data[pos]; + too_large |= utf32_char; + *latin1_output++ = (char)(utf32_char & 0xFF); + pos++; + } + if ((too_large & 0xFFFFFF00) != 0) { + return 0; + } + return latin1_output - start; } -simdutf_constexpr23 auto convert_with_errors(const char32_t* data, size_t len, char* latin1Output) -> result { - char* start{latin1Output}; - size_t pos = 0; - while (pos < len) { +inline simdutf_constexpr23 result convert_with_errors(const char32_t *data, + size_t len, + char *latin1_output) { + char *start{latin1_output}; + size_t pos = 0; + while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval #endif { if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that // they are Latin1 - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0xFFFFFF00FFFFFF00) == 0) { - *latin1Output++ = static_cast(data[pos]); - *latin1Output++ = static_cast(data[pos + 1]); - pos += 2; - continue; - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF00FFFFFF00) == 0) { + *latin1_output++ = char(data[pos]); + *latin1_output++ = char(data[pos + 1]); + pos += 2; + continue; + } } } - uint32_t utf32Char = data[pos]; - if ((utf32Char & 0xFFFFFF00) == 0) { // Check if the character can be represented in Latin-1 - *latin1Output++ = static_cast(utf32Char & 0xFF); - pos++; + uint32_t utf32_char = data[pos]; + if ((utf32_char & 0xFFFFFF00) == + 0) { // Check if the character can be represented in Latin-1 + *latin1_output++ = (char)(utf32_char & 0xFF); + pos++; } else { - return {error_code::TOO_LARGE, pos}; + return result(error_code::TOO_LARGE, pos); }; } - return {error_code::SUCCESS, latin1Output - start}; + return result(error_code::SUCCESS, latin1_output - start); } } // namespace utf32_to_latin1 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf32_to_latin1/utf32_to_latin1.h */ @@ -3008,20 +3152,23 @@ simdutf_constexpr23 auto convert_with_errors(const char32_t* data, size_t len, c #ifndef SIMDUTF_VALID_UTF32_TO_LATIN1_H #define SIMDUTF_VALID_UTF32_TO_LATIN1_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf32_to_latin1 { template -simdutf_constexpr23 auto convert_valid(ReadPtr data, size_t len, WritePtr latin1Output) -> size_t { - static_assert(std::is_same_v, uint32_t>, - "dereferencing the data pointer must result in a uint32_t"); - auto start = latin1Output; - uint32_t utf32Char = 0; - size_t pos = 0; +simdutf_constexpr23 size_t convert_valid(ReadPtr data, size_t len, + WritePtr latin1_output) { + static_assert( + std::is_same::type, uint32_t>::value, + "dereferencing the data pointer must result in a uint32_t"); + auto start = latin1_output; + uint32_t utf32_char; + size_t pos = 0; - while (pos < len) { - utf32Char = data[pos]; + while (pos < len) { + utf32_char = data[pos]; #if SIMDUTF_CPLUSPLUS23 // avoid using the 8 byte at a time optimization in constant evaluation @@ -3031,38 +3178,42 @@ simdutf_constexpr23 auto convert_valid(ReadPtr data, size_t len, WritePtr latin1 #endif if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that they are Latin1 - uint64_t v = 0; + uint64_t v; std::memcpy(&v, data + pos, sizeof(uint64_t)); if ((v & 0xFFFFFF00FFFFFF00) == 0) { - *latin1Output++ = char(data[pos]); - *latin1Output++ = char(data[pos + 1]); - pos += 2; - continue; + *latin1_output++ = char(data[pos]); + *latin1_output++ = char(data[pos + 1]); + pos += 2; + continue; + } else { + // output can not be represented in latin1 + return 0; } - // output can not be represented in latin1 - return 0; } #if SIMDUTF_CPLUSPLUS23 } // if ! consteval #endif - if ((utf32Char & 0xFFFFFF00) == 0) { - *latin1Output++ = static_cast(utf32Char); + if ((utf32_char & 0xFFFFFF00) == 0) { + *latin1_output++ = char(utf32_char); } else { - // output can not be represented in latin1 - return 0; + // output can not be represented in latin1 + return 0; } pos++; } - return latin1Output - start; + return latin1_output - start; } -simdutf_really_inline auto convert_valid(const char32_t* buf, size_t len, char* latin1Output) -> size_t { - return convert_valid(reinterpret_cast(buf), len, latin1Output); +simdutf_really_inline size_t convert_valid(const char32_t *buf, size_t len, + char *latin1_output) { + return convert_valid(reinterpret_cast(buf), len, + latin1_output); } } // namespace utf32_to_latin1 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf32_to_latin1/valid_utf32_to_latin1.h */ @@ -3070,81 +3221,85 @@ simdutf_really_inline auto convert_valid(const char32_t* buf, size_t len, char* #ifndef SIMDUTF_UTF32_TO_UTF16_H #define SIMDUTF_UTF32_TO_UTF16_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf32_to_utf16 { template -simdutf_constexpr23 auto convert(const char32_t* data, size_t len, char16_t* utf16Output) -> size_t { - size_t pos = 0; - char16_t* start{utf16Output}; - while (pos < len) { - uint32_t word = data[pos]; - if ((word & 0xFFFF0000) == 0) { - if (word >= 0xD800 && word <= 0xDFFF) { - return 0; - } - // will not generate a surrogate pair - *utf16Output++ = !match_system(big_endian) - ? static_cast(u16_swap_bytes(static_cast(word))) - : static_cast(word); - } else { - // will generate a surrogate pair - if (word > 0x10FFFF) { - return 0; - } - word -= 0x10000; - auto highSurrogate = static_cast(0xD800 + (word >> 10)); - auto lowSurrogate = static_cast(0xDC00 + (word & 0x3FF)); - if constexpr (!match_system(big_endian)) { - highSurrogate = u16_swap_bytes(highSurrogate); - lowSurrogate = u16_swap_bytes(lowSurrogate); - } - *utf16Output++ = static_cast(highSurrogate); - *utf16Output++ = static_cast(lowSurrogate); - } - pos++; +simdutf_constexpr23 size_t convert(const char32_t *data, size_t len, + char16_t *utf16_output) { + size_t pos = 0; + char16_t *start{utf16_output}; + while (pos < len) { + uint32_t word = data[pos]; + if ((word & 0xFFFF0000) == 0) { + if (word >= 0xD800 && word <= 0xDFFF) { + return 0; + } + // will not generate a surrogate pair + *utf16_output++ = !match_system(big_endian) + ? char16_t(u16_swap_bytes(uint16_t(word))) + : char16_t(word); + } else { + // will generate a surrogate pair + if (word > 0x10FFFF) { + return 0; + } + word -= 0x10000; + uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); + uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); + if constexpr (!match_system(big_endian)) { + high_surrogate = u16_swap_bytes(high_surrogate); + low_surrogate = u16_swap_bytes(low_surrogate); + } + *utf16_output++ = char16_t(high_surrogate); + *utf16_output++ = char16_t(low_surrogate); } - return utf16Output - start; + pos++; + } + return utf16_output - start; } template -simdutf_constexpr23 auto convert_with_errors(const char32_t* data, size_t len, char16_t* utf16Output) -> result { - size_t pos = 0; - char16_t* start{utf16Output}; - while (pos < len) { - uint32_t word = data[pos]; - if ((word & 0xFFFF0000) == 0) { - if (word >= 0xD800 && word <= 0xDFFF) { - return {error_code::SURROGATE, pos}; - } - // will not generate a surrogate pair - *utf16Output++ = !match_system(big_endian) - ? static_cast(u16_swap_bytes(static_cast(word))) - : static_cast(word); - } else { - // will generate a surrogate pair - if (word > 0x10FFFF) { - return {error_code::TOO_LARGE, pos}; - } - word -= 0x10000; - auto highSurrogate = static_cast(0xD800 + (word >> 10)); - auto lowSurrogate = static_cast(0xDC00 + (word & 0x3FF)); - if constexpr (!match_system(big_endian)) { - highSurrogate = u16_swap_bytes(highSurrogate); - lowSurrogate = u16_swap_bytes(lowSurrogate); - } - *utf16Output++ = static_cast(highSurrogate); - *utf16Output++ = static_cast(lowSurrogate); - } - pos++; +simdutf_constexpr23 result convert_with_errors(const char32_t *data, size_t len, + char16_t *utf16_output) { + size_t pos = 0; + char16_t *start{utf16_output}; + while (pos < len) { + uint32_t word = data[pos]; + if ((word & 0xFFFF0000) == 0) { + if (word >= 0xD800 && word <= 0xDFFF) { + return result(error_code::SURROGATE, pos); + } + // will not generate a surrogate pair + *utf16_output++ = !match_system(big_endian) + ? char16_t(u16_swap_bytes(uint16_t(word))) + : char16_t(word); + } else { + // will generate a surrogate pair + if (word > 0x10FFFF) { + return result(error_code::TOO_LARGE, pos); + } + word -= 0x10000; + uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); + uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); + if constexpr (!match_system(big_endian)) { + high_surrogate = u16_swap_bytes(high_surrogate); + low_surrogate = u16_swap_bytes(low_surrogate); + } + *utf16_output++ = char16_t(high_surrogate); + *utf16_output++ = char16_t(low_surrogate); } - return {error_code::SUCCESS, utf16Output - start}; + pos++; + } + return result(error_code::SUCCESS, utf16_output - start); } } // namespace utf32_to_utf16 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf32_to_utf16/utf32_to_utf16.h */ @@ -3152,42 +3307,45 @@ simdutf_constexpr23 auto convert_with_errors(const char32_t* data, size_t len, c #ifndef SIMDUTF_VALID_UTF32_TO_UTF16_H #define SIMDUTF_VALID_UTF32_TO_UTF16_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf32_to_utf16 { template -simdutf_constexpr23 auto convert_valid(const char32_t* data, size_t len, char16_t* utf16Output) -> size_t { - size_t pos = 0; - char16_t* start{utf16Output}; - while (pos < len) { - uint32_t word = data[pos]; - if ((word & 0xFFFF0000) == 0) { - // will not generate a surrogate pair - *utf16Output++ = !match_system(big_endian) - ? static_cast(u16_swap_bytes(static_cast(word))) - : static_cast(word); - pos++; - } else { - // will generate a surrogate pair - word -= 0x10000; - auto highSurrogate = static_cast(0xD800 + (word >> 10)); - auto lowSurrogate = static_cast(0xDC00 + (word & 0x3FF)); - if constexpr (!match_system(big_endian)) { - highSurrogate = u16_swap_bytes(highSurrogate); - lowSurrogate = u16_swap_bytes(lowSurrogate); - } - *utf16Output++ = static_cast(highSurrogate); - *utf16Output++ = static_cast(lowSurrogate); - pos++; - } +simdutf_constexpr23 size_t convert_valid(const char32_t *data, size_t len, + char16_t *utf16_output) { + size_t pos = 0; + char16_t *start{utf16_output}; + while (pos < len) { + uint32_t word = data[pos]; + if ((word & 0xFFFF0000) == 0) { + // will not generate a surrogate pair + *utf16_output++ = !match_system(big_endian) + ? char16_t(u16_swap_bytes(uint16_t(word))) + : char16_t(word); + pos++; + } else { + // will generate a surrogate pair + word -= 0x10000; + uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); + uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); + if constexpr (!match_system(big_endian)) { + high_surrogate = u16_swap_bytes(high_surrogate); + low_surrogate = u16_swap_bytes(low_surrogate); + } + *utf16_output++ = char16_t(high_surrogate); + *utf16_output++ = char16_t(low_surrogate); + pos++; } - return utf16Output - start; + } + return utf16_output - start; } } // namespace utf32_to_utf16 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf32_to_utf16/valid_utf32_to_utf16.h */ @@ -3195,17 +3353,20 @@ simdutf_constexpr23 auto convert_valid(const char32_t* data, size_t len, char16_ #ifndef SIMDUTF_UTF32_TO_UTF8_H #define SIMDUTF_UTF32_TO_UTF8_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf32_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf32 && simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf32 && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + OutputPtr utf8_output) { size_t pos = 0; - auto start = utf8Output; + auto start = utf8_output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -3213,27 +3374,27 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output { // try to convert the next block of 2 ASCII characters if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0xFFFFFF80FFFFFF80) == 0) { - *utf8Output++ = char(data[pos]); - *utf8Output++ = char(data[pos + 1]); - pos += 2; - continue; - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF80FFFFFF80) == 0) { + *utf8_output++ = char(data[pos]); + *utf8_output++ = char(data[pos + 1]); + pos += 2; + continue; + } } } uint32_t word = data[pos]; if ((word & 0xFFFFFF80) == 0) { // will generate one UTF-8 bytes - *utf8Output++ = static_cast(word); + *utf8_output++ = char(word); pos++; } else if ((word & 0xFFFFF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 6) | 0b11000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xFFFF0000) == 0) { // will generate three UTF-8 bytes @@ -3241,9 +3402,9 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output if (word >= 0xD800 && word <= 0xDFFF) { return 0; } - *utf8Output++ = static_cast((word >> 12) | 0b11100000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else { // will generate four UTF-8 bytes @@ -3251,23 +3412,25 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr utf8Output if (word > 0x10FFFF) { return 0; } - *utf8Output++ = static_cast((word >> 18) | 0b11110000); - *utf8Output++ = static_cast(((word >> 12) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 18) | 0b11110000); + *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } } - return utf8Output - start; + return utf8_output - start; } template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf32 && simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf32 && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPtr utf8Output) -> result { +simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, + OutputPtr utf8_output) { size_t pos = 0; - auto start = utf8Output; + auto start = utf8_output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -3275,57 +3438,58 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPt { // try to convert the next block of 2 ASCII characters if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0xFFFFFF80FFFFFF80) == 0) { - *utf8Output++ = char(data[pos]); - *utf8Output++ = char(data[pos + 1]); - pos += 2; - continue; - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF80FFFFFF80) == 0) { + *utf8_output++ = char(data[pos]); + *utf8_output++ = char(data[pos + 1]); + pos += 2; + continue; + } } } uint32_t word = data[pos]; if ((word & 0xFFFFFF80) == 0) { // will generate one UTF-8 bytes - *utf8Output++ = static_cast(word); + *utf8_output++ = char(word); pos++; } else if ((word & 0xFFFFF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 6) | 0b11000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xFFFF0000) == 0) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX if (word >= 0xD800 && word <= 0xDFFF) { - return {error_code::SURROGATE, pos}; + return result(error_code::SURROGATE, pos); } - *utf8Output++ = static_cast((word >> 12) | 0b11100000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else { // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX if (word > 0x10FFFF) { - return {error_code::TOO_LARGE, pos}; + return result(error_code::TOO_LARGE, pos); } - *utf8Output++ = static_cast((word >> 18) | 0b11110000); - *utf8Output++ = static_cast(((word >> 12) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 18) | 0b11110000); + *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } } - return result(error_code::SUCCESS, utf8Output - start); + return result(error_code::SUCCESS, utf8_output - start); } } // namespace utf32_to_utf8 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf32_to_utf8/utf32_to_utf8.h */ @@ -3333,17 +3497,20 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, OutputPt #ifndef SIMDUTF_VALID_UTF32_TO_UTF8_H #define SIMDUTF_VALID_UTF32_TO_UTF8_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf32_to_utf8 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_utf32 && simdutf::detail::index_assignable_from_char) + requires(simdutf::detail::indexes_into_utf32 && + simdutf::detail::index_assignable_from_char) #endif -simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8Output) -> size_t { +simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, + OutputPtr utf8_output) { size_t pos = 0; - auto start = utf8Output; + auto start = utf8_output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -3351,51 +3518,52 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8 { // try to convert the next block of 2 ASCII characters if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0xFFFFFF80FFFFFF80) == 0) { - *utf8Output++ = char(data[pos]); - *utf8Output++ = char(data[pos + 1]); - pos += 2; - continue; - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF80FFFFFF80) == 0) { + *utf8_output++ = char(data[pos]); + *utf8_output++ = char(data[pos + 1]); + pos += 2; + continue; + } } } uint32_t word = data[pos]; if ((word & 0xFFFFFF80) == 0) { // will generate one UTF-8 bytes - *utf8Output++ = static_cast(word); + *utf8_output++ = char(word); pos++; } else if ((word & 0xFFFFF800) == 0) { // will generate two UTF-8 bytes // we have 0b110XXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 6) | 0b11000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else if ((word & 0xFFFF0000) == 0) { // will generate three UTF-8 bytes // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 12) | 0b11100000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } else { // will generate four UTF-8 bytes // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - *utf8Output++ = static_cast((word >> 18) | 0b11110000); - *utf8Output++ = static_cast(((word >> 12) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast(((word >> 6) & 0b111111) | 0b10000000); - *utf8Output++ = static_cast((word & 0b111111) | 0b10000000); + *utf8_output++ = char((word >> 18) | 0b11110000); + *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); pos++; } } - return utf8Output - start; + return utf8_output - start; } } // namespace utf32_to_utf8 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf32_to_utf8/valid_utf32_to_utf8.h */ @@ -3403,36 +3571,39 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, OutputPtr utf8 #ifndef SIMDUTF_UTF8_H #define SIMDUTF_UTF8_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf8 { // credit: based on code from Google Fuchsia (Apache Licensed) template -simdutf_constexpr23 simdutf_warn_unused auto validate(BytePtr data, size_t len) noexcept -> bool { - static_assert(std::is_same_v, uint8_t>, - "dereferencing the data pointer must result in a uint8_t"); - uint64_t pos = 0; - uint32_t codePoint = 0; - while (pos < len) { - uint64_t nextPos = 0; +simdutf_constexpr23 simdutf_warn_unused bool validate(BytePtr data, + size_t len) noexcept { + static_assert( + std::is_same::type, uint8_t>::value, + "dereferencing the data pointer must result in a uint8_t"); + uint64_t pos = 0; + uint32_t code_point = 0; + while (pos < len) { + uint64_t next_pos; #if SIMDUTF_CPLUSPLUS23 if !consteval #endif { // check if the next 16 bytes are ascii. - nextPos = pos + 16; - if (nextPos <= len) { // if it is safe to read 16 more bytes, check - // that they are ascii - uint64_t v1{}; - std::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2{}; - std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - pos = nextPos; - continue; - } + next_pos = pos + 16; + if (next_pos <= len) { // if it is safe to read 16 more bytes, check + // that they are ascii + uint64_t v1{}; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2{}; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + pos = next_pos; + continue; } + } } unsigned char byte = data[pos]; @@ -3445,23 +3616,23 @@ simdutf_constexpr23 simdutf_warn_unused auto validate(BytePtr data, size_t len) } if ((byte & 0b11100000) == 0b11000000) { - nextPos = pos + 2; - if (nextPos > len) { - return false; - } + next_pos = pos + 2; + if (next_pos > len) { + return false; + } if ((data[pos + 1] & 0b11000000) != 0b10000000) { return false; } // range check - codePoint = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); - if ((codePoint < 0x80) || (0x7ff < codePoint)) { - return false; + code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); + if ((code_point < 0x80) || (0x7ff < code_point)) { + return false; } } else if ((byte & 0b11110000) == 0b11100000) { - nextPos = pos + 3; - if (nextPos > len) { - return false; - } + next_pos = pos + 3; + if (next_pos > len) { + return false; + } if ((data[pos + 1] & 0b11000000) != 0b10000000) { return false; } @@ -3469,15 +3640,18 @@ simdutf_constexpr23 simdutf_warn_unused auto validate(BytePtr data, size_t len) return false; } // range check - codePoint = (byte & 0b00001111) << 12 | (data[pos + 1] & 0b00111111) << 6 | (data[pos + 2] & 0b00111111); - if ((codePoint < 0x800) || (0xffff < codePoint) || (0xd7ff < codePoint && codePoint < 0xe000)) { - return false; + code_point = (byte & 0b00001111) << 12 | + (data[pos + 1] & 0b00111111) << 6 | + (data[pos + 2] & 0b00111111); + if ((code_point < 0x800) || (0xffff < code_point) || + (0xd7ff < code_point && code_point < 0xe000)) { + return false; } } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 - nextPos = pos + 4; - if (nextPos > len) { - return false; - } + next_pos = pos + 4; + if (next_pos > len) { + return false; + } if ((data[pos + 1] & 0b11000000) != 0b10000000) { return false; } @@ -3488,122 +3662,132 @@ simdutf_constexpr23 simdutf_warn_unused auto validate(BytePtr data, size_t len) return false; } // range check - codePoint = (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | (data[pos + 2] & 0b00111111) << 6 | - (data[pos + 3] & 0b00111111); - if (codePoint <= 0xffff || 0x10ffff < codePoint) { - return false; + code_point = + (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | + (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); + if (code_point <= 0xffff || 0x10ffff < code_point) { + return false; } } else { // we may have a continuation return false; } - pos = nextPos; + pos = next_pos; } return true; } -simdutf_really_inline simdutf_warn_unused auto validate(const char* buf, size_t len) noexcept -> bool { - return validate(reinterpret_cast(buf), len); +simdutf_really_inline simdutf_warn_unused bool validate(const char *buf, + size_t len) noexcept { + return validate(reinterpret_cast(buf), len); } template -simdutf_constexpr23 simdutf_warn_unused auto validate_with_errors(BytePtr data, size_t len) noexcept -> result { - static_assert(std::is_same_v, uint8_t>, - "dereferencing the data pointer must result in a uint8_t"); - size_t pos = 0; - uint32_t codePoint = 0; - while (pos < len) { - // check of the next 16 bytes are ascii. - size_t nextPos = pos + 16; - if (nextPos <= len) { // if it is safe to read 16 more bytes, check that they are ascii - uint64_t v1 = 0; - std::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - pos = nextPos; - continue; - } - } - unsigned char byte = data[pos]; - - while (byte < 0b10000000) { - if (++pos == len) { - return {error_code::SUCCESS, len}; - } - byte = data[pos]; - } +simdutf_constexpr23 simdutf_warn_unused result +validate_with_errors(BytePtr data, size_t len) noexcept { + static_assert( + std::is_same::type, uint8_t>::value, + "dereferencing the data pointer must result in a uint8_t"); + size_t pos = 0; + uint32_t code_point = 0; + while (pos < len) { + // check of the next 16 bytes are ascii. + size_t next_pos = pos + 16; + if (next_pos <= + len) { // if it is safe to read 16 more bytes, check that they are ascii + uint64_t v1; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + pos = next_pos; + continue; + } + } + unsigned char byte = data[pos]; - if ((byte & 0b11100000) == 0b11000000) { - nextPos = pos + 2; - if (nextPos > len) { - return {error_code::TOO_SHORT, pos}; - } - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - // range check - codePoint = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); - if ((codePoint < 0x80) || (0x7ff < codePoint)) { - return {error_code::OVERLONG, pos}; - } - } else if ((byte & 0b11110000) == 0b11100000) { - nextPos = pos + 3; - if (nextPos > len) { - return {error_code::TOO_SHORT, pos}; - } - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((data[pos + 2] & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - // range check - codePoint = (byte & 0b00001111) << 12 | (data[pos + 1] & 0b00111111) << 6 | (data[pos + 2] & 0b00111111); - if ((codePoint < 0x800) || (0xffff < codePoint)) { - return {error_code::OVERLONG, pos}; - } - if (0xd7ff < codePoint && codePoint < 0xe000) { - return {error_code::SURROGATE, pos}; - } - } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 - nextPos = pos + 4; - if (nextPos > len) { - return {error_code::TOO_SHORT, pos}; - } - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((data[pos + 2] & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((data[pos + 3] & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - // range check - codePoint = (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | - (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); - if (codePoint <= 0xffff) { - return {error_code::OVERLONG, pos}; - } - if (0x10ffff < codePoint) { - return {error_code::TOO_LARGE, pos}; - } - } else { - // we either have too many continuation bytes or an invalid leading byte - if ((byte & 0b11000000) == 0b10000000) { - return {error_code::TOO_LONG, pos}; - } - return result(error_code::HEADER_BITS, pos); - } - pos = nextPos; + while (byte < 0b10000000) { + if (++pos == len) { + return result(error_code::SUCCESS, len); + } + byte = data[pos]; + } + + if ((byte & 0b11100000) == 0b11000000) { + next_pos = pos + 2; + if (next_pos > len) { + return result(error_code::TOO_SHORT, pos); + } + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + // range check + code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); + if ((code_point < 0x80) || (0x7ff < code_point)) { + return result(error_code::OVERLONG, pos); + } + } else if ((byte & 0b11110000) == 0b11100000) { + next_pos = pos + 3; + if (next_pos > len) { + return result(error_code::TOO_SHORT, pos); + } + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + // range check + code_point = (byte & 0b00001111) << 12 | + (data[pos + 1] & 0b00111111) << 6 | + (data[pos + 2] & 0b00111111); + if ((code_point < 0x800) || (0xffff < code_point)) { + return result(error_code::OVERLONG, pos); + } + if (0xd7ff < code_point && code_point < 0xe000) { + return result(error_code::SURROGATE, pos); + } + } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 + next_pos = pos + 4; + if (next_pos > len) { + return result(error_code::TOO_SHORT, pos); + } + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((data[pos + 3] & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + // range check + code_point = + (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | + (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); + if (code_point <= 0xffff) { + return result(error_code::OVERLONG, pos); + } + if (0x10ffff < code_point) { + return result(error_code::TOO_LARGE, pos); + } + } else { + // we either have too many continuation bytes or an invalid leading byte + if ((byte & 0b11000000) == 0b10000000) { + return result(error_code::TOO_LONG, pos); + } else { + return result(error_code::HEADER_BITS, pos); + } } - return {error_code::SUCCESS, len}; + pos = next_pos; + } + return result(error_code::SUCCESS, len); } -simdutf_really_inline simdutf_warn_unused auto validate_with_errors(const char* buf, size_t len) noexcept -> result { - return validate_with_errors(reinterpret_cast(buf), len); +simdutf_really_inline simdutf_warn_unused result +validate_with_errors(const char *buf, size_t len) noexcept { + return validate_with_errors(reinterpret_cast(buf), len); } // Finds the previous leading byte starting backward from buf and validates with @@ -3611,33 +3795,34 @@ simdutf_really_inline simdutf_warn_unused auto validate_with_errors(const char* // chunk is detected We assume that the stream starts with a leading byte, and // to check that it is the case, we ask that you pass a pointer to the start of // the stream (start). -inline simdutf_warn_unused auto rewind_and_validate_with_errors(const char* start, const char* buf, size_t len) noexcept - -> result { - // First check that we start with a leading byte - if ((*start & 0b11000000) == 0b10000000) { - return {error_code::TOO_LONG, 0}; - } - size_t extra_len{0}; - // A leading byte cannot be further than 4 bytes away - for (int i = 0; i < 5; i++) { - unsigned char byte = *buf; - if ((byte & 0b11000000) != 0b10000000) { - break; - } - buf--; - extra_len++; +inline simdutf_warn_unused result rewind_and_validate_with_errors( + const char *start, const char *buf, size_t len) noexcept { + // First check that we start with a leading byte + if ((*start & 0b11000000) == 0b10000000) { + return result(error_code::TOO_LONG, 0); + } + size_t extra_len{0}; + // A leading byte cannot be further than 4 bytes away + for (int i = 0; i < 5; i++) { + unsigned char byte = *buf; + if ((byte & 0b11000000) != 0b10000000) { + break; + } else { + buf--; + extra_len++; } + } - result res = validate_with_errors(buf, len + extra_len); - res.count -= extra_len; - return res; + result res = validate_with_errors(buf, len + extra_len); + res.count -= extra_len; + return res; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto count_code_points(InputPtr data, size_t len) -> size_t { +simdutf_constexpr23 size_t count_code_points(InputPtr data, size_t len) { size_t counter{0}; for (size_t i = 0; i < len; i++) { // -65 is 0b10111111, anything larger in two-complement's should start a new @@ -3651,9 +3836,9 @@ simdutf_constexpr23 auto count_code_points(InputPtr data, size_t len) -> size_t template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto utf16_length_from_utf8(InputPtr data, size_t len) -> size_t { +simdutf_constexpr23 size_t utf16_length_from_utf8(InputPtr data, size_t len) { size_t counter{0}; for (size_t i = 0; i < len; i++) { if (int8_t(data[i]) > -65) { @@ -3668,9 +3853,10 @@ simdutf_constexpr23 auto utf16_length_from_utf8(InputPtr data, size_t len) -> si template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_warn_unused simdutf_constexpr23 auto trim_partial_utf8(InputPtr input, size_t length) -> size_t { +simdutf_warn_unused simdutf_constexpr23 size_t +trim_partial_utf8(InputPtr input, size_t length) { if (length < 3) { switch (length) { case 2: @@ -3704,7 +3890,8 @@ simdutf_warn_unused simdutf_constexpr23 auto trim_partial_utf8(InputPtr input, s } // namespace utf8 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf8.h */ @@ -3712,17 +3899,20 @@ simdutf_warn_unused simdutf_constexpr23 auto trim_partial_utf8(InputPtr input, s #ifndef SIMDUTF_UTF8_TO_LATIN1_H #define SIMDUTF_UTF8_TO_LATIN1_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf8_to_latin1 { template #if SIMDUTF_CPLUSPLUS20 - requires(simdutf::detail::indexes_into_byte_like && simdutf::detail::indexes_into_byte_like) + requires(simdutf::detail::indexes_into_byte_like && + simdutf::detail::indexes_into_byte_like) #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr latinOutput) -> size_t { +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + OutputPtr latin_output) { size_t pos = 0; - auto start = latinOutput; + auto start = latin_output; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -3732,68 +3922,72 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, OutputPtr latinOutpu // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 // 1000 1000 .... etc if ((v & 0x8080808080808080) == 0) { // if NONE of these are set, e.g. all of them are zero, then // everything is ASCII - size_t finalPos = pos + 16; - while (pos < finalPos) { - *latinOutput++ = char(data[pos]); - pos++; - } + size_t final_pos = pos + 16; + while (pos < final_pos) { + *latin_output++ = char(data[pos]); + pos++; + } continue; } } } // suppose it is not an all ASCII byte sequence - uint8_t leadingByte = data[pos]; // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *latinOutput++ = static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { // the first three bits indicate: - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } // checks if the next byte is a valid continuation byte in UTF-8. A + uint8_t leading_byte = data[pos]; // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *latin_output++ = char(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == + 0b11000000) { // the first three bits indicate: + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } // checks if the next byte is a valid continuation byte in UTF-8. A // valid continuation byte starts with 10. // range check - - uint32_t codePoint = (leadingByte & 0b00011111) << 6 | - (data[pos + 1] & 0b00111111); // assembles the Unicode code point from the two bytes. - // It does this by discarding the leading 110 and 10 - // bits from the two bytes, shifting the remaining bits - // of the first byte, and then combining the results - // with a bitwise OR operation. - if (codePoint < 0x80 || 0xFF < codePoint) { - return 0; // We only care about the range 129-255 which is Non-ASCII - // latin1 characters. A code_point beneath 0x80 is invalid as - // it is already covered by bytes whose leading bit is zero. - } - *latinOutput++ = static_cast(codePoint); - pos += 2; + uint32_t code_point = + (leading_byte & 0b00011111) << 6 | + (data[pos + 1] & + 0b00111111); // assembles the Unicode code point from the two bytes. + // It does this by discarding the leading 110 and 10 + // bits from the two bytes, shifting the remaining bits + // of the first byte, and then combining the results + // with a bitwise OR operation. + if (code_point < 0x80 || 0xFF < code_point) { + return 0; // We only care about the range 129-255 which is Non-ASCII + // latin1 characters. A code_point beneath 0x80 is invalid as + // it is already covered by bytes whose leading bit is zero. + } + *latin_output++ = char(code_point); + pos += 2; } else { - return 0; + return 0; } } - return latinOutput - start; + return latin_output - start; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char* latinOutput) -> result { +simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, + char *latin_output) { size_t pos = 0; - char* start{latinOutput}; + char *start{latin_output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -3803,123 +3997,128 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char* la // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 // 1000 1000...etc if ((v & 0x8080808080808080) == 0) { // if NONE of these are set, e.g. all of them are zero, then // everything is ASCII - size_t finalPos = pos + 16; - while (pos < finalPos) { - *latinOutput++ = char(data[pos]); - pos++; - } + size_t final_pos = pos + 16; + while (pos < final_pos) { + *latin_output++ = char(data[pos]); + pos++; + } continue; } } } // suppose it is not an all ASCII byte sequence - uint8_t leadingByte = data[pos]; // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *latinOutput++ = static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { // the first three bits indicate: - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - return {error_code::TOO_SHORT, pos}; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } // checks if the next byte is a valid continuation byte in UTF-8. A + uint8_t leading_byte = data[pos]; // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *latin_output++ = char(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == + 0b11000000) { // the first three bits indicate: + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return result(error_code::TOO_SHORT, pos); + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } // checks if the next byte is a valid continuation byte in UTF-8. A // valid continuation byte starts with 10. // range check - - uint32_t codePoint = (leadingByte & 0b00011111) << 6 | - (data[pos + 1] & 0b00111111); // assembles the Unicode code point from the two bytes. - // It does this by discarding the leading 110 and 10 - // bits from the two bytes, shifting the remaining bits - // of the first byte, and then combining the results - // with a bitwise OR operation. - if (codePoint < 0x80) { - return {error_code::OVERLONG, pos}; - } - if (0xFF < codePoint) { - return {error_code::TOO_LARGE, pos}; - } // We only care about the range 129-255 which is Non-ASCII latin1 + uint32_t code_point = + (leading_byte & 0b00011111) << 6 | + (data[pos + 1] & + 0b00111111); // assembles the Unicode code point from the two bytes. + // It does this by discarding the leading 110 and 10 + // bits from the two bytes, shifting the remaining bits + // of the first byte, and then combining the results + // with a bitwise OR operation. + if (code_point < 0x80) { + return result(error_code::OVERLONG, pos); + } + if (0xFF < code_point) { + return result(error_code::TOO_LARGE, pos); + } // We only care about the range 129-255 which is Non-ASCII latin1 // characters - *latinOutput++ = static_cast(codePoint); - pos += 2; - } else if ((leadingByte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8 - return {error_code::TOO_LARGE, pos}; - } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - return {error_code::TOO_LARGE, pos}; + *latin_output++ = char(code_point); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + return result(error_code::TOO_LARGE, pos); + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + return result(error_code::TOO_LARGE, pos); } else { - // we either have too many continuation bytes or an invalid leading byte - if ((leadingByte & 0b11000000) == 0b10000000) { - return {error_code::TOO_LONG, pos}; - } + // we either have too many continuation bytes or an invalid leading byte + if ((leading_byte & 0b11000000) == 0b10000000) { + return result(error_code::TOO_LONG, pos); + } - return {error_code::HEADER_BITS, pos}; + return result(error_code::HEADER_BITS, pos); + } + } + return result(error_code::SUCCESS, latin_output - start); +} + +inline result rewind_and_convert_with_errors(size_t prior_bytes, + const char *buf, size_t len, + char *latin1_output) { + size_t extra_len{0}; + // We potentially need to go back in time and find a leading byte. + // In theory '3' would be sufficient, but sometimes the error can go back + // quite far. + size_t how_far_back = prior_bytes; + // size_t how_far_back = 3; // 3 bytes in the past + current position + // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } + bool found_leading_bytes{false}; + // important: it is i <= how_far_back and not 'i < how_far_back'. + for (size_t i = 0; i <= how_far_back; i++) { + unsigned char byte = buf[-static_cast(i)]; + found_leading_bytes = ((byte & 0b11000000) != 0b10000000); + if (found_leading_bytes) { + if (i > 0 && byte < 128) { + // If we had to go back and the leading byte is ascii + // then we can stop right away. + return result(error_code::TOO_LONG, 0 - i + 1); + } + buf -= i; + extra_len = i; + break; } } - return {error_code::SUCCESS, latinOutput - start}; -} - -inline auto rewind_and_convert_with_errors(size_t priorBytes, const char* buf, size_t len, char* latin1Output) - -> result { - size_t extraLen{0}; - // We potentially need to go back in time and find a leading byte. - // In theory '3' would be sufficient, but sometimes the error can go back - // quite far. - size_t howFarBack = priorBytes; - // size_t how_far_back = 3; // 3 bytes in the past + current position - // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } - bool foundLeadingBytes{false}; - // important: it is i <= how_far_back and not 'i < how_far_back'. - for (size_t i = 0; i <= howFarBack; i++) { - unsigned char byte = buf[-static_cast(i)]; - foundLeadingBytes = ((byte & 0b11000000) != 0b10000000); - if (foundLeadingBytes) { - if (i > 0 && byte < 128) { - // If we had to go back and the leading byte is ascii - // then we can stop right away. - return {error_code::TOO_LONG, 0 - i + 1}; - } - buf -= i; - extraLen = i; - break; - } - } - // - // It is possible for this function to return a negative count in its result. - // C++ Standard Section 18.1 defines size_t is in which is described - // in C Standard as . C Standard Section 4.1.5 defines size_t as an - // unsigned integral type of the result of the sizeof operator - // - // An unsigned type will simply wrap round arithmetically (well defined). - // - if (!foundLeadingBytes) { - // If how_far_back == 3, we may have four consecutive continuation bytes!!! - // [....] [continuation] [continuation] [continuation] | [buf is - // continuation] Or we possibly have a stream that does not start with a - // leading byte. - return {error_code::TOO_LONG, 0 - howFarBack}; - } - result res = convert_with_errors(buf, len + extraLen, latin1Output); - if (res.error != 0) { - res.count -= extraLen; - } - return res; + // + // It is possible for this function to return a negative count in its result. + // C++ Standard Section 18.1 defines size_t is in which is described + // in C Standard as . C Standard Section 4.1.5 defines size_t as an + // unsigned integral type of the result of the sizeof operator + // + // An unsigned type will simply wrap round arithmetically (well defined). + // + if (!found_leading_bytes) { + // If how_far_back == 3, we may have four consecutive continuation bytes!!! + // [....] [continuation] [continuation] [continuation] | [buf is + // continuation] Or we possibly have a stream that does not start with a + // leading byte. + return result(error_code::TOO_LONG, 0 - how_far_back); + } + result res = convert_with_errors(buf, len + extra_len, latin1_output); + if (res.error) { + res.count -= extra_len; + } + return res; } } // namespace utf8_to_latin1 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf8_to_latin1/utf8_to_latin1.h */ @@ -3927,18 +4126,20 @@ inline auto rewind_and_convert_with_errors(size_t priorBytes, const char* buf, s #ifndef SIMDUTF_VALID_UTF8_TO_LATIN1_H #define SIMDUTF_VALID_UTF8_TO_LATIN1_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf8_to_latin1 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char* latinOutput) -> size_t { +simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, + char *latin_output) { size_t pos = 0; - char* start{latinOutput}; + char *start{latin_output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 @@ -3948,60 +4149,65 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char* latinOut // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 1000 - // 1000, so it makes sense to concatenate everything - if ((v & 0x8080808080808080) == - 0) { // if NONE of these are set, e.g. all of them are zero, then - // everything is ASCII - size_t finalPos = pos + 16; - while (pos < finalPos) { - *latinOutput++ = uint8_t(data[pos]); - pos++; - } - continue; - } + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | + v2}; // We are only interested in these bits: 1000 1000 1000 + // 1000, so it makes sense to concatenate everything + if ((v & 0x8080808080808080) == + 0) { // if NONE of these are set, e.g. all of them are zero, then + // everything is ASCII + size_t final_pos = pos + 16; + while (pos < final_pos) { + *latin_output++ = uint8_t(data[pos]); + pos++; + } + continue; + } } } // suppose it is not an all ASCII byte sequence - auto leadingByte = uint8_t(data[pos]); // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *latinOutput++ = static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { // the first three bits indicate: - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - break; - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return 0; - } // checks if the next byte is a valid continuation byte in UTF-8. A + auto leading_byte = uint8_t(data[pos]); // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *latin_output++ = char(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == + 0b11000000) { // the first three bits indicate: + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + break; + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return 0; + } // checks if the next byte is a valid continuation byte in UTF-8. A // valid continuation byte starts with 10. // range check - - uint32_t codePoint = (leadingByte & 0b00011111) << 6 | - (uint8_t(data[pos + 1]) & 0b00111111); // assembles the Unicode code point from the two bytes. - // It does this by discarding the leading 110 and 10 - // bits from the two bytes, shifting the remaining bits - // of the first byte, and then combining the results - // with a bitwise OR operation. - *latinOutput++ = static_cast(codePoint); - pos += 2; + uint32_t code_point = + (leading_byte & 0b00011111) << 6 | + (uint8_t(data[pos + 1]) & + 0b00111111); // assembles the Unicode code point from the two bytes. + // It does this by discarding the leading 110 and 10 + // bits from the two bytes, shifting the remaining bits + // of the first byte, and then combining the results + // with a bitwise OR operation. + *latin_output++ = char(code_point); + pos += 2; } else { - // we may have a continuation but we do not do error checking - return 0; + // we may have a continuation but we do not do error checking + return 0; } } - return latinOutput - start; + return latin_output - start; } } // namespace utf8_to_latin1 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf8_to_latin1/valid_utf8_to_latin1.h */ @@ -4009,17 +4215,19 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char* latinOut #ifndef SIMDUTF_UTF8_TO_UTF16_H #define SIMDUTF_UTF8_TO_UTF16_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf8_to_utf16 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, char16_t* utf16Output) -> size_t { +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + char16_t *utf16_output) { size_t pos = 0; - char16_t* start{utf16Output}; + char16_t *start{utf16_output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4028,117 +4236,125 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, char16_t* utf16Outpu { if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - size_t finalPos = pos + 16; - while (pos < finalPos) { - *utf16Output++ = !match_system(big_endian) ? char16_t(u16_swap_bytes(data[pos])) - : char16_t(data[pos]); - pos++; - } - continue; - } + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t final_pos = pos + 16; + while (pos < final_pos) { + *utf16_output++ = !match_system(big_endian) + ? char16_t(u16_swap_bytes(data[pos])) + : char16_t(data[pos]); + pos++; + } + continue; + } } } - uint8_t leadingByte = data[pos]; // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *utf16Output++ = !match_system(big_endian) ? static_cast(u16_swap_bytes(leadingByte)) - : static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } - // range check - uint32_t codePoint = (leadingByte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); - if (codePoint < 0x80 || 0x7ff < codePoint) { - return 0; - } - if constexpr (!match_system(big_endian)) { - codePoint = static_cast(u16_swap_bytes(static_cast(codePoint))); - } - *utf16Output++ = static_cast(codePoint); - pos += 2; - } else if ((leadingByte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 2 >= len) { - return 0; - } // minimal bound checking - - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } - if ((data[pos + 2] & 0b11000000) != 0b10000000) { - return 0; - } - // range check - uint32_t codePoint = - (leadingByte & 0b00001111) << 12 | (data[pos + 1] & 0b00111111) << 6 | (data[pos + 2] & 0b00111111); - if (codePoint < 0x800 || 0xffff < codePoint || (0xd7ff < codePoint && codePoint < 0xe000)) { - return 0; - } - if constexpr (!match_system(big_endian)) { - codePoint = static_cast(u16_swap_bytes(static_cast(codePoint))); - } - *utf16Output++ = static_cast(codePoint); - pos += 3; - } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - return 0; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } - if ((data[pos + 2] & 0b11000000) != 0b10000000) { - return 0; - } - if ((data[pos + 3] & 0b11000000) != 0b10000000) { - return 0; - } + uint8_t leading_byte = data[pos]; // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *utf16_output++ = !match_system(big_endian) + ? char16_t(u16_swap_bytes(leading_byte)) + : char16_t(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t code_point = + (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); + if (code_point < 0x80 || 0x7ff < code_point) { + return 0; + } + if constexpr (!match_system(big_endian)) { + code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); + } + *utf16_output++ = char16_t(code_point); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 2 >= len) { + return 0; + } // minimal bound checking - // range check - uint32_t codePoint = (leadingByte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | - (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); - if (codePoint <= 0xffff || 0x10ffff < codePoint) { - return 0; - } - codePoint -= 0x10000; - auto highSurrogate = static_cast(0xD800 + (codePoint >> 10)); - auto lowSurrogate = static_cast(0xDC00 + (codePoint & 0x3FF)); - if constexpr (!match_system(big_endian)) { - highSurrogate = u16_swap_bytes(highSurrogate); - lowSurrogate = u16_swap_bytes(lowSurrogate); - } - *utf16Output++ = static_cast(highSurrogate); - *utf16Output++ = static_cast(lowSurrogate); - pos += 4; - } else { + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t code_point = (leading_byte & 0b00001111) << 12 | + (data[pos + 1] & 0b00111111) << 6 | + (data[pos + 2] & 0b00111111); + if (code_point < 0x800 || 0xffff < code_point || + (0xd7ff < code_point && code_point < 0xe000)) { + return 0; + } + if constexpr (!match_system(big_endian)) { + code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); + } + *utf16_output++ = char16_t(code_point); + pos += 3; + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 3] & 0b11000000) != 0b10000000) { return 0; + } + + // range check + uint32_t code_point = (leading_byte & 0b00000111) << 18 | + (data[pos + 1] & 0b00111111) << 12 | + (data[pos + 2] & 0b00111111) << 6 | + (data[pos + 3] & 0b00111111); + if (code_point <= 0xffff || 0x10ffff < code_point) { + return 0; + } + code_point -= 0x10000; + uint16_t high_surrogate = uint16_t(0xD800 + (code_point >> 10)); + uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); + if constexpr (!match_system(big_endian)) { + high_surrogate = u16_swap_bytes(high_surrogate); + low_surrogate = u16_swap_bytes(low_surrogate); + } + *utf16_output++ = char16_t(high_surrogate); + *utf16_output++ = char16_t(low_surrogate); + pos += 4; + } else { + return 0; } } - return utf16Output - start; + return utf16_output - start; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char16_t* utf16Output) -> result { +simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, + char16_t *utf16_output) { size_t pos = 0; - char16_t* start{utf16Output}; + char16_t *start{utf16_output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4147,118 +4363,125 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char16_t // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - size_t finalPos = pos + 16; - while (pos < finalPos) { - const char16_t byte = uint8_t(data[pos]); - *utf16Output++ = !match_system(big_endian) ? u16_swap_bytes(byte) : byte; - pos++; - } - continue; - } + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t final_pos = pos + 16; + while (pos < final_pos) { + const char16_t byte = uint8_t(data[pos]); + *utf16_output++ = + !match_system(big_endian) ? u16_swap_bytes(byte) : byte; + pos++; + } + continue; + } } } - auto leadingByte = uint8_t(data[pos]); // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *utf16Output++ = !match_system(big_endian) ? static_cast(u16_swap_bytes(leadingByte)) - : static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 1 >= len) { - return {error_code::TOO_SHORT, pos}; - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - // range check - uint32_t codePoint = (leadingByte & 0b00011111) << 6 | (uint8_t(data[pos + 1]) & 0b00111111); - if (codePoint < 0x80 || 0x7ff < codePoint) { - return {error_code::OVERLONG, pos}; - } - if constexpr (!match_system(big_endian)) { - codePoint = static_cast(u16_swap_bytes(static_cast(codePoint))); - } - *utf16Output++ = static_cast(codePoint); - pos += 2; - } else if ((leadingByte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 2 >= len) { - return {error_code::TOO_SHORT, pos}; - } // minimal bound checking - - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - // range check - uint32_t codePoint = (leadingByte & 0b00001111) << 12 | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | - (uint8_t(data[pos + 2]) & 0b00111111); - if ((codePoint < 0x800) || (0xffff < codePoint)) { - return {error_code::OVERLONG, pos}; - } - if (0xd7ff < codePoint && codePoint < 0xe000) { - return {error_code::SURROGATE, pos}; - } - if constexpr (!match_system(big_endian)) { - codePoint = static_cast(u16_swap_bytes(static_cast(codePoint))); - } - *utf16Output++ = static_cast(codePoint); - pos += 3; - } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - return {error_code::TOO_SHORT, pos}; - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } + auto leading_byte = uint8_t(data[pos]); // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *utf16_output++ = !match_system(big_endian) + ? char16_t(u16_swap_bytes(leading_byte)) + : char16_t(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 1 >= len) { + return result(error_code::TOO_SHORT, pos); + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + // range check + uint32_t code_point = (leading_byte & 0b00011111) << 6 | + (uint8_t(data[pos + 1]) & 0b00111111); + if (code_point < 0x80 || 0x7ff < code_point) { + return result(error_code::OVERLONG, pos); + } + if constexpr (!match_system(big_endian)) { + code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); + } + *utf16_output++ = char16_t(code_point); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 2 >= len) { + return result(error_code::TOO_SHORT, pos); + } // minimal bound checking - // range check - uint32_t codePoint = (leadingByte & 0b00000111) << 18 | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | - (uint8_t(data[pos + 2]) & 0b00111111) << 6 | (uint8_t(data[pos + 3]) & 0b00111111); - if (codePoint <= 0xffff) { - return {error_code::OVERLONG, pos}; - } - if (0x10ffff < codePoint) { - return {error_code::TOO_LARGE, pos}; - } - codePoint -= 0x10000; - auto highSurrogate = static_cast(0xD800 + (codePoint >> 10)); - auto lowSurrogate = static_cast(0xDC00 + (codePoint & 0x3FF)); - if constexpr (!match_system(big_endian)) { - highSurrogate = u16_swap_bytes(highSurrogate); - lowSurrogate = u16_swap_bytes(lowSurrogate); - } - *utf16Output++ = static_cast(highSurrogate); - *utf16Output++ = static_cast(lowSurrogate); - pos += 4; + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + // range check + uint32_t code_point = (leading_byte & 0b00001111) << 12 | + (uint8_t(data[pos + 1]) & 0b00111111) << 6 | + (uint8_t(data[pos + 2]) & 0b00111111); + if ((code_point < 0x800) || (0xffff < code_point)) { + return result(error_code::OVERLONG, pos); + } + if (0xd7ff < code_point && code_point < 0xe000) { + return result(error_code::SURROGATE, pos); + } + if constexpr (!match_system(big_endian)) { + code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); + } + *utf16_output++ = char16_t(code_point); + pos += 3; + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return result(error_code::TOO_SHORT, pos); + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + + // range check + uint32_t code_point = (leading_byte & 0b00000111) << 18 | + (uint8_t(data[pos + 1]) & 0b00111111) << 12 | + (uint8_t(data[pos + 2]) & 0b00111111) << 6 | + (uint8_t(data[pos + 3]) & 0b00111111); + if (code_point <= 0xffff) { + return result(error_code::OVERLONG, pos); + } + if (0x10ffff < code_point) { + return result(error_code::TOO_LARGE, pos); + } + code_point -= 0x10000; + uint16_t high_surrogate = uint16_t(0xD800 + (code_point >> 10)); + uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); + if constexpr (!match_system(big_endian)) { + high_surrogate = u16_swap_bytes(high_surrogate); + low_surrogate = u16_swap_bytes(low_surrogate); + } + *utf16_output++ = char16_t(high_surrogate); + *utf16_output++ = char16_t(low_surrogate); + pos += 4; } else { - // we either have too many continuation bytes or an invalid leading byte - if ((leadingByte & 0b11000000) == 0b10000000) { - return {error_code::TOO_LONG, pos}; - } + // we either have too many continuation bytes or an invalid leading byte + if ((leading_byte & 0b11000000) == 0b10000000) { + return result(error_code::TOO_LONG, pos); + } else { return result(error_code::HEADER_BITS, pos); + } } } - return {error_code::SUCCESS, utf16Output - start}; + return result(error_code::SUCCESS, utf16_output - start); } /** @@ -4277,56 +4500,58 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char16_t * contain in the result will be SIZE_T - 1, SIZE_T - 2, or SIZE_T - 3. */ template -inline auto rewind_and_convert_with_errors(size_t priorBytes, const char* buf, size_t len, char16_t* utf16Output) - -> result { - size_t extraLen{0}; - // We potentially need to go back in time and find a leading byte. - // In theory '3' would be sufficient, but sometimes the error can go back - // quite far. - size_t howFarBack = priorBytes; - // size_t how_far_back = 3; // 3 bytes in the past + current position - // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } - bool foundLeadingBytes{false}; - // important: it is i <= how_far_back and not 'i < how_far_back'. - for (size_t i = 0; i <= howFarBack; i++) { - unsigned char byte = buf[-static_cast(i)]; - foundLeadingBytes = ((byte & 0b11000000) != 0b10000000); - if (foundLeadingBytes) { - if (i > 0 && byte < 128) { - // If we had to go back and the leading byte is ascii - // then we can stop right away. - return {error_code::TOO_LONG, 0 - i + 1}; - } - buf -= i; - extraLen = i; - break; - } - } - // - // It is possible for this function to return a negative count in its result. - // C++ Standard Section 18.1 defines size_t is in which is described - // in C Standard as . C Standard Section 4.1.5 defines size_t as an - // unsigned integral type of the result of the sizeof operator - // - // An unsigned type will simply wrap round arithmetically (well defined). - // - if (!foundLeadingBytes) { - // If how_far_back == 3, we may have four consecutive continuation bytes!!! - // [....] [continuation] [continuation] [continuation] | [buf is - // continuation] Or we possibly have a stream that does not start with a - // leading byte. - return {error_code::TOO_LONG, 0 - howFarBack}; - } - result res = convert_with_errors(buf, len + extraLen, utf16Output); - if (res.error) { - res.count -= extraLen; +inline result rewind_and_convert_with_errors(size_t prior_bytes, + const char *buf, size_t len, + char16_t *utf16_output) { + size_t extra_len{0}; + // We potentially need to go back in time and find a leading byte. + // In theory '3' would be sufficient, but sometimes the error can go back + // quite far. + size_t how_far_back = prior_bytes; + // size_t how_far_back = 3; // 3 bytes in the past + current position + // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } + bool found_leading_bytes{false}; + // important: it is i <= how_far_back and not 'i < how_far_back'. + for (size_t i = 0; i <= how_far_back; i++) { + unsigned char byte = buf[-static_cast(i)]; + found_leading_bytes = ((byte & 0b11000000) != 0b10000000); + if (found_leading_bytes) { + if (i > 0 && byte < 128) { + // If we had to go back and the leading byte is ascii + // then we can stop right away. + return result(error_code::TOO_LONG, 0 - i + 1); + } + buf -= i; + extra_len = i; + break; } - return res; + } + // + // It is possible for this function to return a negative count in its result. + // C++ Standard Section 18.1 defines size_t is in which is described + // in C Standard as . C Standard Section 4.1.5 defines size_t as an + // unsigned integral type of the result of the sizeof operator + // + // An unsigned type will simply wrap round arithmetically (well defined). + // + if (!found_leading_bytes) { + // If how_far_back == 3, we may have four consecutive continuation bytes!!! + // [....] [continuation] [continuation] [continuation] | [buf is + // continuation] Or we possibly have a stream that does not start with a + // leading byte. + return result(error_code::TOO_LONG, 0 - how_far_back); + } + result res = convert_with_errors(buf, len + extra_len, utf16_output); + if (res.error) { + res.count -= extra_len; + } + return res; } } // namespace utf8_to_utf16 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf8_to_utf16/utf8_to_utf16.h */ @@ -4334,17 +4559,19 @@ inline auto rewind_and_convert_with_errors(size_t priorBytes, const char* buf, s #ifndef SIMDUTF_VALID_UTF8_TO_UTF16_H #define SIMDUTF_VALID_UTF8_TO_UTF16_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf8_to_utf16 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char16_t* utf16Output) -> size_t { +simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, + char16_t *utf16_output) { size_t pos = 0; - char16_t* start{utf16Output}; + char16_t *start{utf16_output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4352,79 +4579,87 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char16_t* utf1 { // try to convert the next block of 8 ASCII bytes if (pos + 8 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0x8080808080808080) == 0) { - size_t finalPos = pos + 8; - while (pos < finalPos) { - const char16_t byte = uint8_t(data[pos]); - *utf16Output++ = !match_system(big_endian) ? u16_swap_bytes(byte) : byte; - pos++; - } - continue; - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0x8080808080808080) == 0) { + size_t final_pos = pos + 8; + while (pos < final_pos) { + const char16_t byte = uint8_t(data[pos]); + *utf16_output++ = + !match_system(big_endian) ? u16_swap_bytes(byte) : byte; + pos++; + } + continue; + } } } - auto leadingByte = uint8_t(data[pos]); // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *utf16Output++ = !match_system(big_endian) ? static_cast(u16_swap_bytes(leadingByte)) - : static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 1 >= len) { - break; - } // minimal bound checking - auto codePoint = uint16_t(((leadingByte & 0b00011111) << 6) | (uint8_t(data[pos + 1]) & 0b00111111)); - if constexpr (!match_system(big_endian)) { - codePoint = u16_swap_bytes(codePoint); - } - *utf16Output++ = static_cast(codePoint); - pos += 2; - } else if ((leadingByte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8, it should become - // a single UTF-16 word. - if (pos + 2 >= len) { - break; - } // minimal bound checking - auto codePoint = uint16_t(((leadingByte & 0b00001111) << 12) | ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | - (uint8_t(data[pos + 2]) & 0b00111111)); - if constexpr (!match_system(big_endian)) { - codePoint = u16_swap_bytes(codePoint); - } - *utf16Output++ = static_cast(codePoint); - pos += 3; - } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - break; - } // minimal bound checking - uint32_t codePoint = ((leadingByte & 0b00000111) << 18) | ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | - ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | (uint8_t(data[pos + 3]) & 0b00111111); - codePoint -= 0x10000; - auto highSurrogate = static_cast(0xD800 + (codePoint >> 10)); - auto lowSurrogate = static_cast(0xDC00 + (codePoint & 0x3FF)); - if constexpr (!match_system(big_endian)) { - highSurrogate = u16_swap_bytes(highSurrogate); - lowSurrogate = u16_swap_bytes(lowSurrogate); - } - *utf16Output++ = static_cast(highSurrogate); - *utf16Output++ = static_cast(lowSurrogate); - pos += 4; + auto leading_byte = uint8_t(data[pos]); // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *utf16_output++ = !match_system(big_endian) + ? char16_t(u16_swap_bytes(leading_byte)) + : char16_t(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 1 >= len) { + break; + } // minimal bound checking + uint16_t code_point = uint16_t(((leading_byte & 0b00011111) << 6) | + (uint8_t(data[pos + 1]) & 0b00111111)); + if constexpr (!match_system(big_endian)) { + code_point = u16_swap_bytes(uint16_t(code_point)); + } + *utf16_output++ = char16_t(code_point); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8, it should become + // a single UTF-16 word. + if (pos + 2 >= len) { + break; + } // minimal bound checking + uint16_t code_point = + uint16_t(((leading_byte & 0b00001111) << 12) | + ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | + (uint8_t(data[pos + 2]) & 0b00111111)); + if constexpr (!match_system(big_endian)) { + code_point = u16_swap_bytes(uint16_t(code_point)); + } + *utf16_output++ = char16_t(code_point); + pos += 3; + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + break; + } // minimal bound checking + uint32_t code_point = ((leading_byte & 0b00000111) << 18) | + ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | + ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | + (uint8_t(data[pos + 3]) & 0b00111111); + code_point -= 0x10000; + uint16_t high_surrogate = uint16_t(0xD800 + (code_point >> 10)); + uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); + if constexpr (!match_system(big_endian)) { + high_surrogate = u16_swap_bytes(high_surrogate); + low_surrogate = u16_swap_bytes(low_surrogate); + } + *utf16_output++ = char16_t(high_surrogate); + *utf16_output++ = char16_t(low_surrogate); + pos += 4; } else { - // we may have a continuation but we do not do error checking - return 0; + // we may have a continuation but we do not do error checking + return 0; } } - return utf16Output - start; + return utf16_output - start; } } // namespace utf8_to_utf16 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf8_to_utf16/valid_utf8_to_utf16.h */ @@ -4432,17 +4667,19 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char16_t* utf1 #ifndef SIMDUTF_UTF8_TO_UTF32_H #define SIMDUTF_UTF8_TO_UTF32_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf8_to_utf32 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert(InputPtr data, size_t len, char32_t* utf32Output) -> size_t { +simdutf_constexpr23 size_t convert(InputPtr data, size_t len, + char32_t *utf32_output) { size_t pos = 0; - char32_t* start{utf32Output}; + char32_t *start{utf32_output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4451,98 +4688,104 @@ simdutf_constexpr23 auto convert(InputPtr data, size_t len, char32_t* utf32Outpu // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - size_t finalPos = pos + 16; - while (pos < finalPos) { - *utf32Output++ = uint8_t(data[pos]); - pos++; - } - continue; - } + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t final_pos = pos + 16; + while (pos < final_pos) { + *utf32_output++ = uint8_t(data[pos]); + pos++; + } + continue; + } } } - auto leadingByte = uint8_t(data[pos]); // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *utf32Output++ = static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - return 0; - } // minimal bound checking - if ((data[pos + 1] & 0b11000000) != 0b10000000) { - return 0; - } - // range check - uint32_t codePoint = (leadingByte & 0b00011111) << 6 | (uint8_t(data[pos + 1]) & 0b00111111); - if (codePoint < 0x80 || 0x7ff < codePoint) { - return 0; - } - *utf32Output++ = static_cast(codePoint); - pos += 2; - } else if ((leadingByte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8 - if (pos + 2 >= len) { - return 0; - } // minimal bound checking - - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return 0; - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return 0; - } - // range check - uint32_t codePoint = (leadingByte & 0b00001111) << 12 | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | - (uint8_t(data[pos + 2]) & 0b00111111); - if (codePoint < 0x800 || 0xffff < codePoint || (0xd7ff < codePoint && codePoint < 0xe000)) { - return 0; - } - *utf32Output++ = static_cast(codePoint); - pos += 3; - } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - return 0; - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return 0; - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return 0; - } - if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { - return 0; - } + auto leading_byte = uint8_t(data[pos]); // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *utf32_output++ = char32_t(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t code_point = (leading_byte & 0b00011111) << 6 | + (uint8_t(data[pos + 1]) & 0b00111111); + if (code_point < 0x80 || 0x7ff < code_point) { + return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + if (pos + 2 >= len) { + return 0; + } // minimal bound checking + + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return 0; + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t code_point = (leading_byte & 0b00001111) << 12 | + (uint8_t(data[pos + 1]) & 0b00111111) << 6 | + (uint8_t(data[pos + 2]) & 0b00111111); + if (code_point < 0x800 || 0xffff < code_point || + (0xd7ff < code_point && code_point < 0xe000)) { + return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 3; + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return 0; + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return 0; + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return 0; + } + if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { + return 0; + } - // range check - uint32_t codePoint = (leadingByte & 0b00000111) << 18 | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | - (uint8_t(data[pos + 2]) & 0b00111111) << 6 | (uint8_t(data[pos + 3]) & 0b00111111); - if (codePoint <= 0xffff || 0x10ffff < codePoint) { - return 0; - } - *utf32Output++ = static_cast(codePoint); - pos += 4; - } else { + // range check + uint32_t code_point = (leading_byte & 0b00000111) << 18 | + (uint8_t(data[pos + 1]) & 0b00111111) << 12 | + (uint8_t(data[pos + 2]) & 0b00111111) << 6 | + (uint8_t(data[pos + 3]) & 0b00111111); + if (code_point <= 0xffff || 0x10ffff < code_point) { return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 4; + } else { + return 0; } } - return utf32Output - start; + return utf32_output - start; } template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char32_t* utf32Output) -> result { +simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, + char32_t *utf32_output) { size_t pos = 0; - char32_t* start{utf32Output}; + char32_t *start{utf32_output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4551,99 +4794,104 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char32_t // try to convert the next block of 16 ASCII bytes if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that // they are ascii - uint64_t v1 = 0; - ::memcpy(&v1, data + pos, sizeof(uint64_t)); - uint64_t v2 = 0; - ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); - uint64_t v{v1 | v2}; - if ((v & 0x8080808080808080) == 0) { - size_t finalPos = pos + 16; - while (pos < finalPos) { - *utf32Output++ = uint8_t(data[pos]); - pos++; - } - continue; - } + uint64_t v1; + ::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t final_pos = pos + 16; + while (pos < final_pos) { + *utf32_output++ = uint8_t(data[pos]); + pos++; + } + continue; + } } } - auto leadingByte = uint8_t(data[pos]); // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *utf32Output++ = static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - return {error_code::TOO_SHORT, pos}; - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - // range check - uint32_t codePoint = (leadingByte & 0b00011111) << 6 | (uint8_t(data[pos + 1]) & 0b00111111); - if (codePoint < 0x80 || 0x7ff < codePoint) { - return {error_code::OVERLONG, pos}; - } - *utf32Output++ = static_cast(codePoint); - pos += 2; - } else if ((leadingByte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8 - if (pos + 2 >= len) { - return {error_code::TOO_SHORT, pos}; - } // minimal bound checking - - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - // range check - uint32_t codePoint = (leadingByte & 0b00001111) << 12 | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | - (uint8_t(data[pos + 2]) & 0b00111111); - if (codePoint < 0x800 || 0xffff < codePoint) { - return {error_code::OVERLONG, pos}; - } - if (0xd7ff < codePoint && codePoint < 0xe000) { - return {error_code::SURROGATE, pos}; - } - *utf32Output++ = static_cast(codePoint); - pos += 3; - } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - return {error_code::TOO_SHORT, pos}; - } // minimal bound checking - if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } - if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { - return {error_code::TOO_SHORT, pos}; - } + auto leading_byte = uint8_t(data[pos]); // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *utf32_output++ = char32_t(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return result(error_code::TOO_SHORT, pos); + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + // range check + uint32_t code_point = (leading_byte & 0b00011111) << 6 | + (uint8_t(data[pos + 1]) & 0b00111111); + if (code_point < 0x80 || 0x7ff < code_point) { + return result(error_code::OVERLONG, pos); + } + *utf32_output++ = char32_t(code_point); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + if (pos + 2 >= len) { + return result(error_code::TOO_SHORT, pos); + } // minimal bound checking - // range check - uint32_t codePoint = (leadingByte & 0b00000111) << 18 | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | - (uint8_t(data[pos + 2]) & 0b00111111) << 6 | (uint8_t(data[pos + 3]) & 0b00111111); - if (codePoint <= 0xffff) { - return {error_code::OVERLONG, pos}; - } - if (0x10ffff < codePoint) { - return {error_code::TOO_LARGE, pos}; - } - *utf32Output++ = static_cast(codePoint); - pos += 4; + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + // range check + uint32_t code_point = (leading_byte & 0b00001111) << 12 | + (uint8_t(data[pos + 1]) & 0b00111111) << 6 | + (uint8_t(data[pos + 2]) & 0b00111111); + if (code_point < 0x800 || 0xffff < code_point) { + return result(error_code::OVERLONG, pos); + } + if (0xd7ff < code_point && code_point < 0xe000) { + return result(error_code::SURROGATE, pos); + } + *utf32_output++ = char32_t(code_point); + pos += 3; + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return result(error_code::TOO_SHORT, pos); + } // minimal bound checking + if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { + return result(error_code::TOO_SHORT, pos); + } + + // range check + uint32_t code_point = (leading_byte & 0b00000111) << 18 | + (uint8_t(data[pos + 1]) & 0b00111111) << 12 | + (uint8_t(data[pos + 2]) & 0b00111111) << 6 | + (uint8_t(data[pos + 3]) & 0b00111111); + if (code_point <= 0xffff) { + return result(error_code::OVERLONG, pos); + } + if (0x10ffff < code_point) { + return result(error_code::TOO_LARGE, pos); + } + *utf32_output++ = char32_t(code_point); + pos += 4; } else { - // we either have too many continuation bytes or an invalid leading byte - if ((leadingByte & 0b11000000) == 0b10000000) { - return {error_code::TOO_LONG, pos}; - } + // we either have too many continuation bytes or an invalid leading byte + if ((leading_byte & 0b11000000) == 0b10000000) { + return result(error_code::TOO_LONG, pos); + } else { return result(error_code::HEADER_BITS, pos); + } } } - return {error_code::SUCCESS, utf32Output - start}; + return result(error_code::SUCCESS, utf32_output - start); } /** @@ -4661,54 +4909,58 @@ simdutf_constexpr23 auto convert_with_errors(InputPtr data, size_t len, char32_t * If the error is believed to have occurred prior to 'buf', the count value * contain in the result will be SIZE_T - 1, SIZE_T - 2, or SIZE_T - 3. */ -inline auto rewind_and_convert_with_errors(size_t prior_bytes, const char* buf, size_t len, char32_t* utf32Output) - -> result { - size_t extraLen{0}; - // We potentially need to go back in time and find a leading byte. - size_t how_far_back = 3; // 3 bytes in the past + current position - how_far_back = std::min(how_far_back, prior_bytes); - bool foundLeadingBytes{false}; - // important: it is i <= how_far_back and not 'i < how_far_back'. - for (size_t i = 0; i <= how_far_back; i++) { - unsigned char byte = buf[-static_cast(i)]; - foundLeadingBytes = ((byte & 0b11000000) != 0b10000000); - if (foundLeadingBytes) { - if (i > 0 && byte < 128) { - // If we had to go back and the leading byte is ascii - // then we can stop right away. - return {error_code::TOO_LONG, 0 - i + 1}; - } - buf -= i; - extraLen = i; - break; - } - } - // - // It is possible for this function to return a negative count in its result. - // C++ Standard Section 18.1 defines size_t is in which is described - // in C Standard as . C Standard Section 4.1.5 defines size_t as an - // unsigned integral type of the result of the sizeof operator - // - // An unsigned type will simply wrap round arithmetically (well defined). - // - if (!foundLeadingBytes) { - // If how_far_back == 3, we may have four consecutive continuation bytes!!! - // [....] [continuation] [continuation] [continuation] | [buf is - // continuation] Or we possibly have a stream that does not start with a - // leading byte. - return {error_code::TOO_LONG, 0 - how_far_back}; +inline result rewind_and_convert_with_errors(size_t prior_bytes, + const char *buf, size_t len, + char32_t *utf32_output) { + size_t extra_len{0}; + // We potentially need to go back in time and find a leading byte. + size_t how_far_back = 3; // 3 bytes in the past + current position + if (how_far_back > prior_bytes) { + how_far_back = prior_bytes; + } + bool found_leading_bytes{false}; + // important: it is i <= how_far_back and not 'i < how_far_back'. + for (size_t i = 0; i <= how_far_back; i++) { + unsigned char byte = buf[-static_cast(i)]; + found_leading_bytes = ((byte & 0b11000000) != 0b10000000); + if (found_leading_bytes) { + if (i > 0 && byte < 128) { + // If we had to go back and the leading byte is ascii + // then we can stop right away. + return result(error_code::TOO_LONG, 0 - i + 1); + } + buf -= i; + extra_len = i; + break; } + } + // + // It is possible for this function to return a negative count in its result. + // C++ Standard Section 18.1 defines size_t is in which is described + // in C Standard as . C Standard Section 4.1.5 defines size_t as an + // unsigned integral type of the result of the sizeof operator + // + // An unsigned type will simply wrap round arithmetically (well defined). + // + if (!found_leading_bytes) { + // If how_far_back == 3, we may have four consecutive continuation bytes!!! + // [....] [continuation] [continuation] [continuation] | [buf is + // continuation] Or we possibly have a stream that does not start with a + // leading byte. + return result(error_code::TOO_LONG, 0 - how_far_back); + } - result res = convert_with_errors(buf, len + extraLen, utf32Output); - if (res.error != 0) { - res.count -= extraLen; - } - return res; + result res = convert_with_errors(buf, len + extra_len, utf32_output); + if (res.error) { + res.count -= extra_len; + } + return res; } } // namespace utf8_to_utf32 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf8_to_utf32/utf8_to_utf32.h */ @@ -4716,17 +4968,19 @@ inline auto rewind_and_convert_with_errors(size_t prior_bytes, const char* buf, #ifndef SIMDUTF_VALID_UTF8_TO_UTF32_H #define SIMDUTF_VALID_UTF8_TO_UTF32_H -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace utf8_to_utf32 { template #if SIMDUTF_CPLUSPLUS20 - requires simdutf::detail::indexes_into_byte_like + requires simdutf::detail::indexes_into_byte_like #endif -simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char32_t* utf32Output) -> size_t { +simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, + char32_t *utf32_output) { size_t pos = 0; - char32_t* start{utf32Output}; + char32_t *start{utf32_output}; while (pos < len) { #if SIMDUTF_CPLUSPLUS23 if !consteval @@ -4735,65 +4989,71 @@ simdutf_constexpr23 auto convert_valid(InputPtr data, size_t len, char32_t* utf3 // try to convert the next block of 8 ASCII bytes if (pos + 8 <= len) { // if it is safe to read 8 more bytes, check that // they are ascii - uint64_t v = 0; - ::memcpy(&v, data + pos, sizeof(uint64_t)); - if ((v & 0x8080808080808080) == 0) { - size_t finalPos = pos + 8; - while (pos < finalPos) { - *utf32Output++ = uint8_t(data[pos]); - pos++; - } - continue; - } + uint64_t v; + ::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0x8080808080808080) == 0) { + size_t final_pos = pos + 8; + while (pos < final_pos) { + *utf32_output++ = uint8_t(data[pos]); + pos++; + } + continue; + } } } - auto leadingByte = uint8_t(data[pos]); // leading byte - if (leadingByte < 0b10000000) { - // converting one ASCII byte !!! - *utf32Output++ = static_cast(leadingByte); - pos++; - } else if ((leadingByte & 0b11100000) == 0b11000000) { - // We have a two-byte UTF-8 - if (pos + 1 >= len) { - break; - } // minimal bound checking - *utf32Output++ = char32_t(((leadingByte & 0b00011111) << 6) | (uint8_t(data[pos + 1]) & 0b00111111)); - pos += 2; - } else if ((leadingByte & 0b11110000) == 0b11100000) { - // We have a three-byte UTF-8 - if (pos + 2 >= len) { - break; - } // minimal bound checking - *utf32Output++ = char32_t(((leadingByte & 0b00001111) << 12) | ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | - (uint8_t(data[pos + 2]) & 0b00111111)); - pos += 3; - } else if ((leadingByte & 0b11111000) == 0b11110000) { // 0b11110000 - // we have a 4-byte UTF-8 word. - if (pos + 3 >= len) { - break; - } // minimal bound checking - uint32_t codeWord = ((leadingByte & 0b00000111) << 18) | ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | - ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | (uint8_t(data[pos + 3]) & 0b00111111); - *utf32Output++ = static_cast(codeWord); - pos += 4; + auto leading_byte = uint8_t(data[pos]); // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *utf32_output++ = char32_t(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + break; + } // minimal bound checking + *utf32_output++ = char32_t(((leading_byte & 0b00011111) << 6) | + (uint8_t(data[pos + 1]) & 0b00111111)); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + if (pos + 2 >= len) { + break; + } // minimal bound checking + *utf32_output++ = char32_t(((leading_byte & 0b00001111) << 12) | + ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | + (uint8_t(data[pos + 2]) & 0b00111111)); + pos += 3; + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + break; + } // minimal bound checking + uint32_t code_word = ((leading_byte & 0b00000111) << 18) | + ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | + ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | + (uint8_t(data[pos + 3]) & 0b00111111); + *utf32_output++ = char32_t(code_word); + pos += 4; } else { - // we may have a continuation but we do not do error checking - return 0; + // we may have a continuation but we do not do error checking + return 0; } } - return utf32Output - start; + return utf32_output - start; } } // namespace utf8_to_utf32 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/utf8_to_utf32/valid_utf8_to_utf32.h */ namespace simdutf { -constexpr size_t defaultLineLength = 76; ///< default line length for base64 encoding with lines +constexpr size_t default_line_length = + 76; ///< default line length for base64 encoding with lines #if SIMDUTF_FEATURE_DETECT_ENCODING /** @@ -4806,12 +5066,13 @@ constexpr size_t defaultLineLength = 76; ///< default line length for base64 enc * @param length the length of the string in bytes. * @return the detected encoding type */ -simdutf_warn_unused auto autodetect_encoding(const char* input, size_t length) noexcept -> simdutf::encoding_type; -simdutf_really_inline simdutf_warn_unused auto autodetect_encoding(const uint8_t* input, size_t length) noexcept - -> simdutf::encoding_type { - return autodetect_encoding(reinterpret_cast(input), length); +simdutf_warn_unused simdutf::encoding_type +autodetect_encoding(const char *input, size_t length) noexcept; +simdutf_really_inline simdutf_warn_unused simdutf::encoding_type +autodetect_encoding(const uint8_t *input, size_t length) noexcept { + return autodetect_encoding(reinterpret_cast(input), length); } -#if SIMDUTF_SPAN + #if SIMDUTF_SPAN /** * Autodetect the encoding of the input, a single encoding is recommended. * E.g., the function might return simdutf::encoding_type::UTF8, @@ -4823,11 +5084,13 @@ simdutf_really_inline simdutf_warn_unused auto autodetect_encoding(const uint8_t * std::string_view, std::vector, std::span etc. * @return the detected encoding type */ -simdutf_really_inline simdutf_warn_unused auto autodetect_encoding( - const detail::input_span_of_byte_like auto& input) noexcept -> simdutf::encoding_type { - return autodetect_encoding(reinterpret_cast(input.data()), input.size()); +simdutf_really_inline simdutf_warn_unused simdutf::encoding_type +autodetect_encoding( + const detail::input_span_of_byte_like auto &input) noexcept { + return autodetect_encoding(reinterpret_cast(input.data()), + input.size()); } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Autodetect the possible encodings of the input in one pass. @@ -4840,16 +5103,19 @@ simdutf_really_inline simdutf_warn_unused auto autodetect_encoding( * @param length the length of the string in bytes. * @return the detected encoding type */ -simdutf_warn_unused auto detect_encodings(const char* input, size_t length) noexcept -> int; -simdutf_really_inline simdutf_warn_unused auto detect_encodings(const uint8_t* input, size_t length) noexcept -> int { - return detect_encodings(reinterpret_cast(input), length); +simdutf_warn_unused int detect_encodings(const char *input, + size_t length) noexcept; +simdutf_really_inline simdutf_warn_unused int +detect_encodings(const uint8_t *input, size_t length) noexcept { + return detect_encodings(reinterpret_cast(input), length); } -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused auto detect_encodings( - const detail::input_span_of_byte_like auto& input) noexcept -> int { - return detect_encodings(reinterpret_cast(input.data()), input.size()); + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused int +detect_encodings(const detail::input_span_of_byte_like auto &input) noexcept { + return detect_encodings(reinterpret_cast(input.data()), + input.size()); } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING @@ -4864,21 +5130,22 @@ simdutf_really_inline simdutf_warn_unused auto detect_encodings( * @param len the length of the string in bytes. * @return true if and only if the string is valid UTF-8. */ -simdutf_warn_unused auto validate_utf8(const char* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_constexpr23 simdutf_really_inline - simdutf_warn_unused auto validate_utf8(const detail::input_span_of_byte_like auto& input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::validate(detail::constexpr_cast_ptr(input.data()), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_constexpr23 simdutf_really_inline simdutf_warn_unused bool +validate_utf8(const detail::input_span_of_byte_like auto &input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::validate( + detail::constexpr_cast_ptr(input.data()), input.size()); + } else + #endif + { return validate_utf8(reinterpret_cast(input.data()), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 @@ -4894,21 +5161,24 @@ simdutf_constexpr23 simdutf_really_inline * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused auto validate_utf8_with_errors(const char* buf, size_t len) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto validate_utf8_with_errors( - const detail::input_span_of_byte_like auto& input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::validate_with_errors(detail::constexpr_cast_ptr(input.data()), input.size()); - } else -#endif - { +simdutf_warn_unused result validate_utf8_with_errors(const char *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result +validate_utf8_with_errors( + const detail::input_span_of_byte_like auto &input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::validate_with_errors( + detail::constexpr_cast_ptr(input.data()), input.size()); + } else + #endif + { return validate_utf8_with_errors( reinterpret_cast(input.data()), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_ASCII @@ -4921,21 +5191,22 @@ simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto validate_utf8 * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ -simdutf_warn_unused auto validate_ascii(const char* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_ascii(const detail::input_span_of_byte_like auto& input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::ascii::validate(detail::constexpr_cast_ptr(input.data()), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_ascii(const char *buf, size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool +validate_ascii(const detail::input_span_of_byte_like auto &input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::ascii::validate( + detail::constexpr_cast_ptr(input.data()), input.size()); + } else + #endif + { return validate_ascii(reinterpret_cast(input.data()), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Validate the ASCII string and stop on error. It might be faster than @@ -4950,22 +5221,24 @@ simdutf_really_inline simdutf_warn_unused * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused auto validate_ascii_with_errors(const char* buf, size_t len) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto validate_ascii_with_errors( - const detail::input_span_of_byte_like auto& input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::ascii::validate_with_errors(detail::constexpr_cast_ptr(input.data()), - input.size()); - } else -#endif - { +simdutf_warn_unused result validate_ascii_with_errors(const char *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +validate_ascii_with_errors( + const detail::input_span_of_byte_like auto &input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::ascii::validate_with_errors( + detail::constexpr_cast_ptr(input.data()), input.size()); + } else + #endif + { return validate_ascii_with_errors( reinterpret_cast(input.data()), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII @@ -4980,20 +5253,22 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto validate_asci * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ -simdutf_warn_unused auto validate_utf16_as_ascii(const char16_t* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf16_as_ascii(std::span input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_as_ascii(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_utf16_as_ascii(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool +validate_utf16_as_ascii(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_as_ascii(input.data(), + input.size()); + } else + #endif + { return validate_utf16_as_ascii(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Validate the ASCII string as a UTF-16BE sequence. @@ -5006,20 +5281,22 @@ simdutf_really_inline simdutf_warn_unused * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ -simdutf_warn_unused auto validate_utf16be_as_ascii(const char16_t* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf16be_as_ascii(std::span input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_as_ascii(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_utf16be_as_ascii(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool +validate_utf16be_as_ascii(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_as_ascii(input.data(), + input.size()); + } else + #endif + { return validate_utf16be_as_ascii(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Validate the ASCII string as a UTF-16LE sequence. @@ -5032,20 +5309,22 @@ simdutf_really_inline simdutf_warn_unused * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ -simdutf_warn_unused auto validate_utf16le_as_ascii(const char16_t* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf16le_as_ascii(std::span input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_as_ascii(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_utf16le_as_ascii(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool +validate_utf16le_as_ascii(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_as_ascii(input.data(), + input.size()); + } else + #endif + { return validate_utf16le_as_ascii(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 @@ -5063,20 +5342,22 @@ simdutf_really_inline simdutf_warn_unused * (char16_t). * @return true if and only if the string is valid UTF-16. */ -simdutf_warn_unused auto validate_utf16(const char16_t* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf16(std::span input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_utf16(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool +validate_utf16(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate(input.data(), + input.size()); + } else + #endif + { return validate_utf16(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING @@ -5094,20 +5375,22 @@ simdutf_really_inline simdutf_warn_unused * (char16_t). * @return true if and only if the string is valid UTF-16LE. */ -simdutf_warn_unused auto validate_utf16le(const char16_t* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 - simdutf_warn_unused auto validate_utf16le(std::span input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_utf16le(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused bool +validate_utf16le(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate(input.data(), + input.size()); + } else + #endif + { return validate_utf16le(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF16 @@ -5125,20 +5408,21 @@ simdutf_really_inline simdutf_constexpr23 * (char16_t). * @return true if and only if the string is valid UTF-16BE. */ -simdutf_warn_unused auto validate_utf16be(const char16_t* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf16be(std::span input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_utf16be(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool +validate_utf16be(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate(input.data(), input.size()); + } else + #endif + { return validate_utf16be(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Using native endianness; Validate the UTF-16 string and stop on error. @@ -5157,20 +5441,22 @@ simdutf_really_inline simdutf_warn_unused * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused auto validate_utf16_with_errors(const char16_t* buf, size_t len) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf16_with_errors(std::span input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_with_errors(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused result validate_utf16_with_errors(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +validate_utf16_with_errors(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_with_errors( + input.data(), input.size()); + } else + #endif + { return validate_utf16_with_errors(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Validate the UTF-16LE string and stop on error. It might be faster than @@ -5188,20 +5474,22 @@ simdutf_really_inline simdutf_warn_unused * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused auto validate_utf16le_with_errors(const char16_t* buf, size_t len) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf16le_with_errors(std::span input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_with_errors(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused result validate_utf16le_with_errors(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +validate_utf16le_with_errors(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_with_errors( + input.data(), input.size()); + } else + #endif + { return validate_utf16le_with_errors(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Validate the UTF-16BE string and stop on error. It might be faster than @@ -5219,20 +5507,22 @@ simdutf_really_inline simdutf_warn_unused * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused auto validate_utf16be_with_errors(const char16_t* buf, size_t len) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf16be_with_errors(std::span input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::validate_with_errors(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused result validate_utf16be_with_errors(const char16_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +validate_utf16be_with_errors(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::validate_with_errors(input.data(), + input.size()); + } else + #endif + { return validate_utf16be_with_errors(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Fixes an ill-formed UTF-16LE string by replacing mismatched surrogates with @@ -5341,20 +5631,22 @@ to_well_formed_utf16(std::span input, * (char32_t). * @return true if and only if the string is valid UTF-32. */ -simdutf_warn_unused auto validate_utf32(const char32_t* buf, size_t len) noexcept -> bool; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf32(std::span input) noexcept -> bool { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32::validate(detail::constexpr_cast_ptr(input.data()), input.size()); - } else -#endif - { +simdutf_warn_unused bool validate_utf32(const char32_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool +validate_utf32(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32::validate( + detail::constexpr_cast_ptr(input.data()), input.size()); + } else + #endif + { return validate_utf32(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF32 @@ -5374,21 +5666,22 @@ simdutf_really_inline simdutf_warn_unused * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused auto validate_utf32_with_errors(const char32_t* buf, size_t len) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto validate_utf32_with_errors(std::span input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32::validate_with_errors(detail::constexpr_cast_ptr(input.data()), - input.size()); - } else -#endif - { +simdutf_warn_unused result validate_utf32_with_errors(const char32_t *buf, + size_t len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +validate_utf32_with_errors(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32::validate_with_errors( + detail::constexpr_cast_ptr(input.data()), input.size()); + } else + #endif + { return validate_utf32_with_errors(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -5402,23 +5695,29 @@ simdutf_really_inline simdutf_warn_unused * @param utf8_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_latin1_to_utf8(const char* input, size_t length, char* utf8Output) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf8( - const detail::input_span_of_byte_like auto& latin1Input, - detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf8::convert(detail::constexpr_cast_ptr(latin1Input.data()), latin1Input.size(), - detail::constexpr_cast_writeptr(utf8Output.data())); - } else -#endif - { - return convert_latin1_to_utf8(reinterpret_cast(latin1Input.data()), latin1Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_latin1_to_utf8(const char *input, + size_t length, + char *utf8_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_latin1_to_utf8( + const detail::input_span_of_byte_like auto &latin1_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf8::convert( + detail::constexpr_cast_ptr(latin1_input.data()), + latin1_input.size(), + detail::constexpr_cast_writeptr(utf8_output.data())); + } else + #endif + { + return convert_latin1_to_utf8( + reinterpret_cast(latin1_input.data()), + latin1_input.size(), reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert Latin1 string into UTF-8 string with output limit. @@ -5433,30 +5732,33 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin * @param utf8_len the maximum output length * @return the number of written char; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_latin1_to_utf8_safe(const char* input, size_t length, char* utf8Output, - size_t utf8Len) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf8_safe( - const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& utf8Output) noexcept - -> size_t { - // implementation note: outputspan is a forwarding ref to avoid copying - // and allow both lvalues and rvalues. std::span can be copied without - // problems, but std::vector should not, and this function should accept - // both. it will allow using an owning rvalue ref (example: passing a - // temporary std::string) as output, but the user will quickly find out - // that he has no way of getting the data out of the object in that case. -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf8::convert_safe_constexpr(input.data(), input.size(), utf8Output.data(), - utf8Output.size()); - } else -#endif - { - return convert_latin1_to_utf8_safe(reinterpret_cast(input.data()), input.size(), - reinterpret_cast(utf8Output.data()), utf8Output.size()); +simdutf_warn_unused size_t +convert_latin1_to_utf8_safe(const char *input, size_t length, char *utf8_output, + size_t utf8_len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_latin1_to_utf8_safe( + const detail::input_span_of_byte_like auto &input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + // implementation note: outputspan is a forwarding ref to avoid copying + // and allow both lvalues and rvalues. std::span can be copied without + // problems, but std::vector should not, and this function should accept + // both. it will allow using an owning rvalue ref (example: passing a + // temporary std::string) as output, but the user will quickly find out + // that he has no way of getting the data out of the object in that case. + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf8::convert_safe_constexpr( + input.data(), input.size(), utf8_output.data(), utf8_output.size()); + } else + #endif + { + return convert_latin1_to_utf8_safe( + reinterpret_cast(input.data()), input.size(), + reinterpret_cast(utf8_output.data()), utf8_output.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -5470,23 +5772,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_latin1_to_utf16le(const char* input, size_t length, char16_t* utf16Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf16le( - const detail::input_span_of_byte_like auto& latin1Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf16::convert(latin1Input.data(), latin1Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_latin1_to_utf16le(reinterpret_cast(latin1Input.data()), latin1Input.size(), - utf16Output.data()); +simdutf_warn_unused size_t convert_latin1_to_utf16le( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_latin1_to_utf16le( + const detail::input_span_of_byte_like auto &latin1_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf16::convert( + latin1_input.data(), latin1_input.size(), utf16_output.data()); + } else + #endif + { + return convert_latin1_to_utf16le( + reinterpret_cast(latin1_input.data()), + latin1_input.size(), utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert Latin1 string into UTF-16BE string. @@ -5498,23 +5803,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_latin1_to_utf16be(const char* input, size_t length, char16_t* utf16Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf16be( - const detail::input_span_of_byte_like auto& input, std::span output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf16::convert(input.data(), input.size(), output.data()); - } else -#endif - { +simdutf_warn_unused size_t convert_latin1_to_utf16be( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_latin1_to_utf16be(const detail::input_span_of_byte_like auto &input, + std::span output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf16::convert( + input.data(), input.size(), output.data()); + } else + #endif + { return convert_latin1_to_utf16be( reinterpret_cast(input.data()), input.size(), output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16 string would require in Latin1 * format. @@ -5523,9 +5830,9 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin * @return the length of the string in Latin1 code units (char) required to * encode the UTF-16 string as Latin1 */ -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto latin1_length_from_utf16(size_t length) noexcept - -> size_t { - return length; +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +latin1_length_from_utf16(size_t length) noexcept { + return length; } /** @@ -5536,9 +5843,9 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto latin1_length * @return the length of the string in 2-byte code units (char16_t) required to * encode the Latin1 string as UTF-16 */ -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf16_length_from_latin1(size_t length) noexcept - -> size_t { - return length; +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf16_length_from_latin1(size_t length) noexcept { + return length; } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -5553,22 +5860,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf16_length_ * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_latin1_to_utf32(const char* input, size_t length, char32_t* utf32Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf32( - const detail::input_span_of_byte_like auto& latin1Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf32::convert(latin1Input.data(), latin1Input.size(), utf32Output.data()); - } else -#endif - { - return convert_latin1_to_utf32(reinterpret_cast(latin1Input.data()), latin1Input.size(), - utf32Output.data()); +simdutf_warn_unused size_t convert_latin1_to_utf32( + const char *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_latin1_to_utf32( + const detail::input_span_of_byte_like auto &latin1_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf32::convert( + latin1_input.data(), latin1_input.size(), utf32_output.data()); + } else + #endif + { + return convert_latin1_to_utf32( + reinterpret_cast(latin1_input.data()), + latin1_input.size(), utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -5584,24 +5895,27 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin * @return the number of written char; 0 if the input was not valid UTF-8 string * or if it cannot be represented as Latin1 */ -simdutf_warn_unused auto convert_utf8_to_latin1(const char* input, size_t length, char* latin1Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_latin1( - const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& output) noexcept - -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_latin1::convert(input.data(), input.size(), output.data()); - } else -#endif - { +simdutf_warn_unused size_t convert_utf8_to_latin1(const char *input, + size_t length, + char *latin1_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf8_to_latin1( + const detail::input_span_of_byte_like auto &input, + detail::output_span_of_byte_like auto &&output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_latin1::convert(input.data(), input.size(), + output.data()); + } else + #endif + { return convert_utf8_to_latin1(reinterpret_cast(input.data()), input.size(), reinterpret_cast(output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -5618,22 +5932,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ -simdutf_warn_unused auto convert_utf8_to_utf16(const char* input, size_t length, char16_t* utf16Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16( - const detail::input_span_of_byte_like auto& input, std::span output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert(input.data(), input.size(), output.data()); - } else -#endif - { +simdutf_warn_unused size_t convert_utf8_to_utf16( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf8_to_utf16(const detail::input_span_of_byte_like auto &input, + std::span output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert( + input.data(), input.size(), output.data()); + } else + #endif + { return convert_utf8_to_utf16(reinterpret_cast(input.data()), input.size(), output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-8 @@ -5652,22 +5968,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ -simdutf_warn_unused auto utf8_length_from_utf16le_with_replacement(const char16_t* input, size_t length) noexcept - -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto utf8_length_from_utf16le_with_replacement( - std::span validUtf16Input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16_with_replacement(validUtf16Input.data(), - validUtf16Input.size()); - } else -#endif - { - return utf8_length_from_utf16le_with_replacement(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( + const char16_t *input, size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result +utf8_length_from_utf16le_with_replacement( + std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16_with_replacement< + endianness::LITTLE>(valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf8_length_from_utf16le_with_replacement(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-8 @@ -5686,22 +6004,24 @@ simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto utf8_length_f * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ -simdutf_warn_unused auto utf8_length_from_utf16be_with_replacement(const char16_t* input, size_t length) noexcept - -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_from_utf16be_with_replacement( - std::span validUtf16Input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16_with_replacement(validUtf16Input.data(), - validUtf16Input.size()); - } else -#endif - { - return utf8_length_from_utf16be_with_replacement(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused result utf8_length_from_utf16be_with_replacement( + const char16_t *input, size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +utf8_length_from_utf16be_with_replacement( + std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16_with_replacement< + endianness::BIG>(valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf8_length_from_utf16be_with_replacement(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -5714,22 +6034,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_f * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t. */ -simdutf_warn_unused auto convert_latin1_to_utf16(const char* input, size_t length, char16_t* utf16Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin1_to_utf16( - const detail::input_span_of_byte_like auto& input, std::span output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf16::convert(input.data(), input.size(), output.data()); - } else -#endif - { +simdutf_warn_unused size_t convert_latin1_to_utf16( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_latin1_to_utf16(const detail::input_span_of_byte_like auto &input, + std::span output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf16::convert( + input.data(), input.size(), output.data()); + } else + #endif + { return convert_latin1_to_utf16(reinterpret_cast(input.data()), input.size(), output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -5745,23 +6067,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_latin * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ -simdutf_warn_unused auto convert_utf8_to_utf16le(const char* input, size_t length, char16_t* utf16Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16le( - const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert(utf8Input.data(), utf8Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf8_to_utf16le(reinterpret_cast(utf8Input.data()), utf8Input.size(), - utf16Output.data()); +simdutf_warn_unused size_t convert_utf8_to_utf16le( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf8_to_utf16le(const detail::input_span_of_byte_like auto &utf8_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert( + utf8_input.data(), utf8_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf8_to_utf16le( + reinterpret_cast(utf8_input.data()), utf8_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16BE string. @@ -5775,22 +6099,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ -simdutf_warn_unused auto convert_utf8_to_utf16be(const char* input, size_t length, char16_t* utf16Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16be( - const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert(utf8Input.data(), utf8Input.size(), utf16Output.data()); - } else -#endif - { - return convert_utf8_to_utf16be(reinterpret_cast(utf8Input.data()), utf8Input.size(), - utf16Output.data()); +simdutf_warn_unused size_t convert_utf8_to_utf16be( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf8_to_utf16be(const detail::input_span_of_byte_like auto &utf8_input, + std::span utf16_output) noexcept { + + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert( + utf8_input.data(), utf8_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf8_to_utf16be( + reinterpret_cast(utf8_input.data()), utf8_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -5810,23 +6138,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * (in the input in code units) if any, or the number of code units validated if * successful. */ -simdutf_warn_unused auto convert_utf8_to_latin1_with_errors(const char* input, size_t length, - char* latin1Output) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_latin1_with_errors( - const detail::input_span_of_byte_like auto& utf8Input, - detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_latin1::convert_with_errors(utf8Input.data(), utf8Input.size(), latin1Output.data()); - } else -#endif - { - return convert_utf8_to_latin1_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused result convert_utf8_to_latin1_with_errors( + const char *input, size_t length, char *latin1_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf8_to_latin1_with_errors( + const detail::input_span_of_byte_like auto &utf8_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_latin1::convert_with_errors( + utf8_input.data(), utf8_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf8_to_latin1_with_errors( + reinterpret_cast(utf8_input.data()), utf8_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -5845,23 +6176,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused auto convert_utf8_to_utf16_with_errors(const char* input, size_t length, - char16_t* utf16Output) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16_with_errors( - const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_with_errors(utf8Input.data(), utf8Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf8_to_utf16_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), - utf16Output.data()); +simdutf_warn_unused result convert_utf8_to_utf16_with_errors( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf8_to_utf16_with_errors( + const detail::input_span_of_byte_like auto &utf8_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_with_errors( + utf8_input.data(), utf8_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf8_to_utf16_with_errors( + reinterpret_cast(utf8_input.data()), utf8_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16LE string and stop on error. @@ -5877,23 +6211,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused auto convert_utf8_to_utf16le_with_errors(const char* input, size_t length, - char16_t* utf16Output) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16le_with_errors( - const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_with_errors(utf8Input.data(), utf8Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf8_to_utf16le_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), - utf16Output.data()); +simdutf_warn_unused result convert_utf8_to_utf16le_with_errors( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf8_to_utf16le_with_errors( + const detail::input_span_of_byte_like auto &utf8_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_with_errors( + utf8_input.data(), utf8_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf8_to_utf16le_with_errors( + reinterpret_cast(utf8_input.data()), utf8_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16BE string and stop on error. @@ -5909,23 +6246,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused auto convert_utf8_to_utf16be_with_errors(const char* input, size_t length, - char16_t* utf16Output) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf16be_with_errors( - const detail::input_span_of_byte_like auto& utf8Input, std::span utf16Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_with_errors(utf8Input.data(), utf8Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf8_to_utf16be_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), - utf16Output.data()); +simdutf_warn_unused result convert_utf8_to_utf16be_with_errors( + const char *input, size_t length, char16_t *utf16_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf8_to_utf16be_with_errors( + const detail::input_span_of_byte_like auto &utf8_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_with_errors( + utf8_input.data(), utf8_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf8_to_utf16be_with_errors( + reinterpret_cast(utf8_input.data()), utf8_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -5941,22 +6281,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * @return the number of written char32_t; 0 if the input was not valid UTF-8 * string */ -simdutf_warn_unused auto convert_utf8_to_utf32(const char* input, size_t length, char32_t* utf32Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf32( - const detail::input_span_of_byte_like auto& utf8Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf32::convert(utf8Input.data(), utf8Input.size(), utf32Output.data()); - } else -#endif - { - return convert_utf8_to_utf32(reinterpret_cast(utf8Input.data()), utf8Input.size(), - utf32Output.data()); +simdutf_warn_unused size_t convert_utf8_to_utf32( + const char *input, size_t length, char32_t *utf32_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf8_to_utf32(const detail::input_span_of_byte_like auto &utf8_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf32::convert(utf8_input.data(), utf8_input.size(), + utf32_output.data()); + } else + #endif + { + return convert_utf8_to_utf32( + reinterpret_cast(utf8_input.data()), utf8_input.size(), + utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-32 string and stop on error. @@ -5972,22 +6315,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * (in the input in code units) if any, or the number of char32_t written if * successful. */ -simdutf_warn_unused auto convert_utf8_to_utf32_with_errors(const char* input, size_t length, - char32_t* utf32Output) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_to_utf32_with_errors( - const detail::input_span_of_byte_like auto& utf8Input, std::span utf32Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf32::convert_with_errors(utf8Input.data(), utf8Input.size(), utf32Output.data()); - } else -#endif - { - return convert_utf8_to_utf32_with_errors(reinterpret_cast(utf8Input.data()), utf8Input.size(), - utf32Output.data()); +simdutf_warn_unused result convert_utf8_to_utf32_with_errors( + const char *input, size_t length, char32_t *utf32_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf8_to_utf32_with_errors( + const detail::input_span_of_byte_like auto &utf8_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf32::convert_with_errors( + utf8_input.data(), utf8_input.size(), utf32_output.data()); + } else + #endif + { + return convert_utf8_to_utf32_with_errors( + reinterpret_cast(utf8_input.data()), utf8_input.size(), + utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -6010,23 +6357,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf8_ * @param latin1_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if the input was not valid UTF-8 string */ -simdutf_warn_unused auto convert_valid_utf8_to_latin1(const char* input, size_t length, char* latin1Output) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_latin1( - const detail::input_span_of_byte_like auto& validUtf8Input, - detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_latin1::convert_valid(validUtf8Input.data(), validUtf8Input.size(), latin1Output.data()); - } else -#endif - { - return convert_valid_utf8_to_latin1(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size(), - latin1Output.data()); +simdutf_warn_unused size_t convert_valid_utf8_to_latin1( + const char *input, size_t length, char *latin1_output) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf8_to_latin1( + const detail::input_span_of_byte_like auto &valid_utf8_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_latin1::convert_valid( + valid_utf8_input.data(), valid_utf8_input.size(), latin1_output.data()); + } else + #endif + { + return convert_valid_utf8_to_latin1( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size(), latin1_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6040,23 +6390,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ -simdutf_warn_unused auto convert_valid_utf8_to_utf16(const char* input, size_t length, char16_t* utf16Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_utf16( - const detail::input_span_of_byte_like auto& validUtf8Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_valid(validUtf8Input.data(), validUtf8Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_valid_utf8_to_utf16(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size(), - utf16Output.data()); +simdutf_warn_unused size_t convert_valid_utf8_to_utf16( + const char *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf8_to_utf16( + const detail::input_span_of_byte_like auto &valid_utf8_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_valid( + valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); + } else + #endif + { + return convert_valid_utf8_to_utf16( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size(), utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-8 string into UTF-16LE string. @@ -6068,23 +6421,27 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ -simdutf_warn_unused auto convert_valid_utf8_to_utf16le(const char* input, size_t length, char16_t* utf16Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_utf16le( - const detail::input_span_of_byte_like auto& validUtf8Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_valid(validUtf8Input.data(), validUtf8Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_valid_utf8_to_utf16le(reinterpret_cast(validUtf8Input.data()), - validUtf8Input.size(), utf16Output.data()); +simdutf_warn_unused size_t convert_valid_utf8_to_utf16le( + const char *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf8_to_utf16le( + const detail::input_span_of_byte_like auto &valid_utf8_input, + std::span utf16_output) noexcept { + + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_valid( + valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); + } else + #endif + { + return convert_valid_utf8_to_utf16le( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size(), utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-8 string into UTF-16BE string. @@ -6096,23 +6453,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ -simdutf_warn_unused auto convert_valid_utf8_to_utf16be(const char* input, size_t length, char16_t* utf16Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_utf16be( - const detail::input_span_of_byte_like auto& validUtf8Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf16::convert_valid(validUtf8Input.data(), validUtf8Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_valid_utf8_to_utf16be(reinterpret_cast(validUtf8Input.data()), - validUtf8Input.size(), utf16Output.data()); +simdutf_warn_unused size_t convert_valid_utf8_to_utf16be( + const char *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf8_to_utf16be( + const detail::input_span_of_byte_like auto &valid_utf8_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf16::convert_valid( + valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); + } else + #endif + { + return convert_valid_utf8_to_utf16be( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size(), utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -6126,22 +6486,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t */ -simdutf_warn_unused auto convert_valid_utf8_to_utf32(const char* input, size_t length, char32_t* utf32Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf8_to_utf32( - const detail::input_span_of_byte_like auto& validUtf8Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8_to_utf32::convert_valid(validUtf8Input.data(), validUtf8Input.size(), utf32Output.data()); - } else -#endif - { - return convert_valid_utf8_to_utf32(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size(), - utf32Output.data()); +simdutf_warn_unused size_t convert_valid_utf8_to_utf32( + const char *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf8_to_utf32( + const detail::input_span_of_byte_like auto &valid_utf8_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8_to_utf32::convert_valid( + valid_utf8_input.data(), valid_utf8_input.size(), utf32_output.data()); + } else + #endif + { + return convert_valid_utf8_to_utf32( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size(), utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -6153,20 +6517,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param length the length of the string bytes * @return the number of bytes required to encode the Latin1 string as UTF-8 */ -simdutf_warn_unused auto utf8_length_from_latin1(const char* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_from_latin1( - const detail::input_span_of_byte_like auto& latin1Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::latin1_to_utf8::utf8_length_from_latin1(latin1Input.data(), latin1Input.size()); - } else -#endif - { - return utf8_length_from_latin1(reinterpret_cast(latin1Input.data()), latin1Input.size()); +simdutf_warn_unused size_t utf8_length_from_latin1(const char *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf8_length_from_latin1( + const detail::input_span_of_byte_like auto &latin1_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::latin1_to_utf8::utf8_length_from_latin1(latin1_input.data(), + latin1_input.size()); + } else + #endif + { + return utf8_length_from_latin1( + reinterpret_cast(latin1_input.data()), + latin1_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-8 string would require in Latin1 @@ -6181,20 +6550,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_f * @param length the length of the string in byte * @return the number of bytes required to encode the UTF-8 string as Latin1 */ -simdutf_warn_unused auto latin1_length_from_utf8(const char* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto latin1_length_from_utf8( - const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::count_code_points(validUtf8Input.data(), validUtf8Input.size()); - } else -#endif - { - return latin1_length_from_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); +simdutf_warn_unused size_t latin1_length_from_utf8(const char *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +latin1_length_from_utf8( + const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::count_code_points(valid_utf8_input.data(), + valid_utf8_input.size()); + } else + #endif + { + return latin1_length_from_utf8( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6212,20 +6586,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto latin1_length * @return the number of char16_t code units required to encode the UTF-8 string * as UTF-16LE */ -simdutf_warn_unused auto utf16_length_from_utf8(const char* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf16_length_from_utf8( - const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::utf16_length_from_utf8(validUtf8Input.data(), validUtf8Input.size()); - } else -#endif - { - return utf16_length_from_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); +simdutf_warn_unused size_t utf16_length_from_utf8(const char *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf16_length_from_utf8( + const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::utf16_length_from_utf8(valid_utf8_input.data(), + valid_utf8_input.size()); + } else + #endif + { + return utf16_length_from_utf8( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -6245,20 +6624,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf16_length_ * @return the number of char32_t code units required to encode the UTF-8 string * as UTF-32 */ -simdutf_warn_unused auto utf32_length_from_utf8(const char* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf32_length_from_utf8( - const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::count_code_points(validUtf8Input.data(), validUtf8Input.size()); - } else -#endif - { - return utf32_length_from_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); +simdutf_warn_unused size_t utf32_length_from_utf8(const char *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf32_length_from_utf8( + const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { + + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::count_code_points(valid_utf8_input.data(), + valid_utf8_input.size()); + } else + #endif + { + return utf32_length_from_utf8( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6277,22 +6662,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf32_length_ * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused auto convert_utf16_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf8( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert(utf16Input.data(), utf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_utf16_to_utf8(utf16Input.data(), utf16Input.size(), reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_utf16_to_utf8(const char16_t *input, + size_t length, + char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16_to_utf8( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16_to_utf8(utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-16 string into UTF-8 @@ -6312,33 +6701,41 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @param utf8_len the maximum output length * @return the number of written char; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_utf16_to_utf8_safe(const char16_t* input, size_t length, char* utf8Output, - size_t utf8Len) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf8_safe( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { - // implementation note: outputspan is a forwarding ref to avoid copying - // and allow both lvalues and rvalues. std::span can be copied without - // problems, but std::vector should not, and this function should accept - // both. it will allow using an owning rvalue ref (example: passing a - // temporary std::string) as output, but the user will quickly find out - // that he has no way of getting the data out of the object in that case. -#if SIMDUTF_CPLUSPLUS23 - if consteval { - const full_result r = scalar::utf16_to_utf8::convert_with_errors( - utf16Input.data(), utf16Input.size(), utf8Output.data(), utf8Output.size()); - if (r.error != error_code::SUCCESS && r.error != error_code::OUTPUT_BUFFER_TOO_SMALL) { - return 0; - } - return r.outputCount; - } else -#endif - { - return convert_utf16_to_utf8_safe(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data()), utf8Output.size()); +simdutf_warn_unused size_t convert_utf16_to_utf8_safe(const char16_t *input, + size_t length, + char *utf8_output, + size_t utf8_len) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16_to_utf8_safe( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + // implementation note: outputspan is a forwarding ref to avoid copying + // and allow both lvalues and rvalues. std::span can be copied without + // problems, but std::vector should not, and this function should accept + // both. it will allow using an owning rvalue ref (example: passing a + // temporary std::string) as output, but the user will quickly find out + // that he has no way of getting the data out of the object in that case. + #if SIMDUTF_CPLUSPLUS23 + if consteval { + const full_result r = + scalar::utf16_to_utf8::convert_with_errors( + utf16_input.data(), utf16_input.size(), utf8_output.data(), + utf8_output.size()); + if (r.error != error_code::SUCCESS && + r.error != error_code::OUTPUT_BUFFER_TOO_SMALL) { + return 0; + } + return r.output_count; + } else + #endif + { + return convert_utf16_to_utf8_safe( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data()), utf8_output.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -6357,23 +6754,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @return number of written code units; 0 if input is not a valid UTF-16 string * or if it cannot be represented as Latin1 */ -simdutf_warn_unused auto convert_utf16_to_latin1(const char16_t* input, size_t length, char* latin1Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_latin1( - std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert(utf16Input.data(), utf16Input.size(), - latin1Output.data()); - } else -#endif - { - return convert_utf16_to_latin1(utf16Input.data(), utf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused size_t convert_utf16_to_latin1( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16_to_latin1( + std::span utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert( + utf16_input.data(), utf16_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf16_to_latin1( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into Latin1 string. @@ -6391,23 +6791,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @return number of written code units; 0 if input is not a valid UTF-16LE * string or if it cannot be represented as Latin1 */ -simdutf_warn_unused auto convert_utf16le_to_latin1(const char16_t* input, size_t length, char* latin1Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_latin1( - std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert(utf16Input.data(), utf16Input.size(), - latin1Output.data()); - } else -#endif - { - return convert_utf16le_to_latin1(utf16Input.data(), utf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused size_t convert_utf16le_to_latin1( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16le_to_latin1( + std::span utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert( + utf16_input.data(), utf16_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf16le_to_latin1( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into Latin1 string. @@ -6423,23 +6826,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @return number of written code units; 0 if input is not a valid UTF-16BE * string or if it cannot be represented as Latin1 */ -simdutf_warn_unused auto convert_utf16be_to_latin1(const char16_t* input, size_t length, char* latin1Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_latin1( - std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert(utf16Input.data(), utf16Input.size(), - latin1Output.data()); - } else -#endif - { - return convert_utf16be_to_latin1(utf16Input.data(), utf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused size_t convert_utf16be_to_latin1( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16be_to_latin1( + std::span utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert( + utf16_input.data(), utf16_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf16be_to_latin1( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6457,23 +6863,27 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused auto convert_utf16le_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf8( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert(utf16Input.data(), utf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_utf16le_to_utf8(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_utf16le_to_utf8(const char16_t *input, + size_t length, + char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16le_to_utf8( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16le_to_utf8( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string. @@ -6489,22 +6899,27 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused auto convert_utf16be_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf8( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert(utf16Input.data(), utf16Input.size(), utf8Output.data()); - } else -#endif - { - return convert_utf16be_to_utf8(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_utf16be_to_utf8(const char16_t *input, + size_t length, + char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16be_to_utf8( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16be_to_utf8( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -6524,23 +6939,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused auto convert_utf16_to_latin1_with_errors(const char16_t* input, size_t length, - char* latin1Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_latin1_with_errors( - std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_with_errors(utf16Input.data(), utf16Input.size(), - latin1Output.data()); - } else -#endif - { - return convert_utf16_to_latin1_with_errors(utf16Input.data(), utf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused result convert_utf16_to_latin1_with_errors( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16_to_latin1_with_errors( + std::span utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_with_errors( + utf16_input.data(), utf16_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf16_to_latin1_with_errors( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into Latin1 string. @@ -6557,23 +6975,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused auto convert_utf16le_to_latin1_with_errors(const char16_t* input, size_t length, - char* latin1Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_latin1_with_errors( - std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_with_errors(utf16Input.data(), utf16Input.size(), - latin1Output.data()); - } else -#endif - { - return convert_utf16le_to_latin1_with_errors(utf16Input.data(), utf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused result convert_utf16le_to_latin1_with_errors( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16le_to_latin1_with_errors( + std::span utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_with_errors( + utf16_input.data(), utf16_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf16le_to_latin1_with_errors( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into Latin1 string. @@ -6592,23 +7013,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused auto convert_utf16be_to_latin1_with_errors(const char16_t* input, size_t length, - char* latin1Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_latin1_with_errors( - std::span utf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_with_errors(utf16Input.data(), utf16Input.size(), - latin1Output.data()); - } else -#endif - { - return convert_utf16be_to_latin1_with_errors(utf16Input.data(), utf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused result convert_utf16be_to_latin1_with_errors( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16be_to_latin1_with_errors( + std::span utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_with_errors( + utf16_input.data(), utf16_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf16be_to_latin1_with_errors( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6629,23 +7053,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused auto convert_utf16_to_utf8_with_errors(const char16_t* input, size_t length, - char* utf8Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf8_with_errors( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_errors(utf16Input.data(), utf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_utf16_to_utf8_with_errors(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused result convert_utf16_to_utf8_with_errors( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16_to_utf8_with_errors( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_errors( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16_to_utf8_with_errors( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-8 string and stop on error. @@ -6663,23 +7090,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused auto convert_utf16le_to_utf8_with_errors(const char16_t* input, size_t length, - char* utf8Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf8_with_errors( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_errors(utf16Input.data(), utf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_utf16le_to_utf8_with_errors(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused result convert_utf16le_to_utf8_with_errors( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16le_to_utf8_with_errors( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_errors( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16le_to_utf8_with_errors( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string and stop on error. @@ -6697,23 +7127,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused auto convert_utf16be_to_utf8_with_errors(const char16_t* input, size_t length, - char* utf8Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf8_with_errors( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_errors(utf16Input.data(), utf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_utf16be_to_utf8_with_errors(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused result convert_utf16be_to_utf8_with_errors( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16be_to_utf8_with_errors( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_errors( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16be_to_utf8_with_errors( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-8 string, replacing @@ -6728,24 +7161,27 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units - */ -simdutf_warn_unused auto convert_utf16le_to_utf8_with_replacement(const char16_t* input, size_t length, - char* utf8Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf8_with_replacement( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_replacement(utf16Input.data(), utf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_utf16le_to_utf8_with_replacement(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data())); + */ +simdutf_warn_unused size_t convert_utf16le_to_utf8_with_replacement( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16le_to_utf8_with_replacement( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_replacement( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16le_to_utf8_with_replacement( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string, replacing @@ -6761,23 +7197,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ -simdutf_warn_unused auto convert_utf16be_to_utf8_with_replacement(const char16_t* input, size_t length, - char* utf8Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf8_with_replacement( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_replacement(utf16Input.data(), utf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_utf16be_to_utf8_with_replacement(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_utf16be_to_utf8_with_replacement( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16be_to_utf8_with_replacement( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_replacement( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16be_to_utf8_with_replacement( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16 string (native endianness) into UTF-8 string, @@ -6793,23 +7232,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ -simdutf_warn_unused auto convert_utf16_to_utf8_with_replacement(const char16_t* input, size_t length, - char* utf8Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf8_with_replacement( - std::span utf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_with_replacement(utf16Input.data(), utf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_utf16_to_utf8_with_replacement(utf16Input.data(), utf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_utf16_to_utf8_with_replacement( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16_to_utf8_with_replacement( + std::span utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_with_replacement( + utf16_input.data(), utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf16_to_utf8_with_replacement( + utf16_input.data(), utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6826,23 +7268,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16_to_utf8( - std::span validUtf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_valid(validUtf16Input.data(), validUtf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_valid_utf16_to_utf8(validUtf16Input.data(), validUtf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_valid_utf16_to_utf8( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf16_to_utf8( + std::span valid_utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_valid( + valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_valid_utf16_to_utf8( + valid_utf16_input.data(), valid_utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -6865,25 +7310,28 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16_to_latin1(const char16_t* input, size_t length, - char* latin1Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16_to_latin1( - std::span validUtf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept - -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_valid_impl( - detail::constexpr_cast_ptr(validUtf16Input.data()), validUtf16Input.size(), - detail::constexpr_cast_writeptr(latin1Output.data())); - } else -#endif - { - return convert_valid_utf16_to_latin1(validUtf16Input.data(), validUtf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused size_t convert_valid_utf16_to_latin1( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf16_to_latin1( + std::span valid_utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_valid_impl( + detail::constexpr_cast_ptr(valid_utf16_input.data()), + valid_utf16_input.size(), + detail::constexpr_cast_writeptr(latin1_output.data())); + } else + #endif + { + return convert_valid_utf16_to_latin1( + valid_utf16_input.data(), valid_utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-16LE string into Latin1 string. @@ -6904,25 +7352,28 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16le_to_latin1(const char16_t* input, size_t length, - char* latin1Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid_utf16le_to_latin1( - std::span validUtf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept - -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_valid_impl( - detail::constexpr_cast_ptr(validUtf16Input.data()), validUtf16Input.size(), - detail::constexpr_cast_writeptr(latin1Output.data())); - } else -#endif - { - return convert_valid_utf16le_to_latin1(validUtf16Input.data(), validUtf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused size_t convert_valid_utf16le_to_latin1( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t +convert_valid_utf16le_to_latin1( + std::span valid_utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_valid_impl( + detail::constexpr_cast_ptr(valid_utf16_input.data()), + valid_utf16_input.size(), + detail::constexpr_cast_writeptr(latin1_output.data())); + } else + #endif + { + return convert_valid_utf16le_to_latin1( + valid_utf16_input.data(), valid_utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into Latin1 string. @@ -6943,25 +7394,28 @@ simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16be_to_latin1(const char16_t* input, size_t length, - char* latin1Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid_utf16be_to_latin1( - std::span validUtf16Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept - -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_latin1::convert_valid_impl( - detail::constexpr_cast_ptr(validUtf16Input.data()), validUtf16Input.size(), - detail::constexpr_cast_writeptr(latin1Output.data())); - } else -#endif - { - return convert_valid_utf16be_to_latin1(validUtf16Input.data(), validUtf16Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused size_t convert_valid_utf16be_to_latin1( + const char16_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t +convert_valid_utf16be_to_latin1( + std::span valid_utf16_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_latin1::convert_valid_impl( + detail::constexpr_cast_ptr(valid_utf16_input.data()), + valid_utf16_input.size(), + detail::constexpr_cast_writeptr(latin1_output.data())); + } else + #endif + { + return convert_valid_utf16be_to_latin1( + valid_utf16_input.data(), valid_utf16_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -6978,23 +7432,26 @@ simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16le_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16le_to_utf8( - std::span validUtf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_valid(validUtf16Input.data(), validUtf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_valid_utf16le_to_utf8(validUtf16Input.data(), validUtf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_valid_utf16le_to_utf8( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf16le_to_utf8( + std::span valid_utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_valid( + valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_valid_utf16le_to_utf8( + valid_utf16_input.data(), valid_utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into UTF-8 string. @@ -7009,23 +7466,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16be_to_utf8(const char16_t* input, size_t length, char* utf8Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16be_to_utf8( - std::span validUtf16Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf8::convert_valid(validUtf16Input.data(), validUtf16Input.size(), - utf8Output.data()); - } else -#endif - { - return convert_valid_utf16be_to_utf8(validUtf16Input.data(), validUtf16Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_valid_utf16be_to_utf8( + const char16_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf16be_to_utf8( + std::span valid_utf16_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf8::convert_valid( + valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); + } else + #endif + { + return convert_valid_utf16be_to_utf8( + valid_utf16_input.data(), valid_utf16_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -7044,22 +7504,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused auto convert_utf16_to_utf32(const char16_t* input, size_t length, char32_t* utf32Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf32( - std::span utf16Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert(utf16Input.data(), utf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_utf16_to_utf32(utf16Input.data(), utf16Input.size(), utf32Output.data()); +simdutf_warn_unused size_t convert_utf16_to_utf32( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16_to_utf32(std::span utf16_input, + std::span utf32_output) noexcept { + + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert( + utf16_input.data(), utf16_input.size(), utf32_output.data()); + } else + #endif + { + return convert_utf16_to_utf32(utf16_input.data(), utf16_input.size(), + utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-32 string. @@ -7075,22 +7538,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused auto convert_utf16le_to_utf32(const char16_t* input, size_t length, char32_t* utf32Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf32( - std::span utf16Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert(utf16Input.data(), utf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_utf16le_to_utf32(utf16Input.data(), utf16Input.size(), utf32Output.data()); +simdutf_warn_unused size_t convert_utf16le_to_utf32( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16le_to_utf32(std::span utf16_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert( + utf16_input.data(), utf16_input.size(), utf32_output.data()); + } else + #endif + { + return convert_utf16le_to_utf32(utf16_input.data(), utf16_input.size(), + utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-32 string. @@ -7106,22 +7571,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ -simdutf_warn_unused auto convert_utf16be_to_utf32(const char16_t* input, size_t length, char32_t* utf32Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf32( - std::span utf16Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert(utf16Input.data(), utf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_utf16be_to_utf32(utf16Input.data(), utf16Input.size(), utf32Output.data()); +simdutf_warn_unused size_t convert_utf16be_to_utf32( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf16be_to_utf32(std::span utf16_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert( + utf16_input.data(), utf16_input.size(), utf32_output.data()); + } else + #endif + { + return convert_utf16be_to_utf32(utf16_input.data(), utf16_input.size(), + utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-16 string into @@ -7140,22 +7607,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char32_t written if * successful. */ -simdutf_warn_unused auto convert_utf16_to_utf32_with_errors(const char16_t* input, size_t length, - char32_t* utf32Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16_to_utf32_with_errors( - std::span utf16Input, std::span utf32Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_with_errors(utf16Input.data(), utf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_utf16_to_utf32_with_errors(utf16Input.data(), utf16Input.size(), utf32Output.data()); +simdutf_warn_unused result convert_utf16_to_utf32_with_errors( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16_to_utf32_with_errors(std::span utf16_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_with_errors( + utf16_input.data(), utf16_input.size(), utf32_output.data()); + } else + #endif + { + return convert_utf16_to_utf32_with_errors( + utf16_input.data(), utf16_input.size(), utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-32 string and stop on error. @@ -7173,22 +7642,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char32_t written if * successful. */ -simdutf_warn_unused auto convert_utf16le_to_utf32_with_errors(const char16_t* input, size_t length, - char32_t* utf32Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16le_to_utf32_with_errors( - std::span utf16Input, std::span utf32Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_with_errors(utf16Input.data(), utf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_utf16le_to_utf32_with_errors(utf16Input.data(), utf16Input.size(), utf32Output.data()); +simdutf_warn_unused result convert_utf16le_to_utf32_with_errors( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16le_to_utf32_with_errors( + std::span utf16_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_with_errors( + utf16_input.data(), utf16_input.size(), utf32_output.data()); + } else + #endif + { + return convert_utf16le_to_utf32_with_errors( + utf16_input.data(), utf16_input.size(), utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-32 string and stop on error. @@ -7206,22 +7678,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * (in the input in code units) if any, or the number of char32_t written if * successful. */ -simdutf_warn_unused auto convert_utf16be_to_utf32_with_errors(const char16_t* input, size_t length, - char32_t* utf32Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16be_to_utf32_with_errors( - std::span utf16Input, std::span utf32Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_with_errors(utf16Input.data(), utf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_utf16be_to_utf32_with_errors(utf16Input.data(), utf16Input.size(), utf32Output.data()); +simdutf_warn_unused result convert_utf16be_to_utf32_with_errors( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf16be_to_utf32_with_errors( + std::span utf16_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_with_errors( + utf16_input.data(), utf16_input.size(), utf32_output.data()); + } else + #endif + { + return convert_utf16be_to_utf32_with_errors( + utf16_input.data(), utf16_input.size(), utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Using native endianness, convert valid UTF-16 string into UTF-32 string. @@ -7237,22 +7712,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf16 * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16_to_utf32(const char16_t* input, size_t length, - char32_t* utf32Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16_to_utf32( - std::span validUtf16Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_valid(validUtf16Input.data(), validUtf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_valid_utf16_to_utf32(validUtf16Input.data(), validUtf16Input.size(), utf32Output.data()); +simdutf_warn_unused size_t convert_valid_utf16_to_utf32( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf16_to_utf32(std::span valid_utf16_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_valid( + valid_utf16_input.data(), valid_utf16_input.size(), + utf32_output.data()); + } else + #endif + { + return convert_valid_utf16_to_utf32(valid_utf16_input.data(), + valid_utf16_input.size(), + utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-16LE string into UTF-32 string. @@ -7267,22 +7746,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16le_to_utf32(const char16_t* input, size_t length, - char32_t* utf32Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16le_to_utf32( - std::span validUtf16Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_valid(validUtf16Input.data(), validUtf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_valid_utf16le_to_utf32(validUtf16Input.data(), validUtf16Input.size(), utf32Output.data()); +simdutf_warn_unused size_t convert_valid_utf16le_to_utf32( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf16le_to_utf32(std::span valid_utf16_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_valid( + valid_utf16_input.data(), valid_utf16_input.size(), + utf32_output.data()); + } else + #endif + { + return convert_valid_utf16le_to_utf32(valid_utf16_input.data(), + valid_utf16_input.size(), + utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into UTF-32 string. @@ -7297,22 +7780,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf16be_to_utf32(const char16_t* input, size_t length, - char32_t* utf32Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf16be_to_utf32( - std::span validUtf16Input, std::span utf32Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16_to_utf32::convert_valid(validUtf16Input.data(), validUtf16Input.size(), - utf32Output.data()); - } else -#endif - { - return convert_valid_utf16be_to_utf32(validUtf16Input.data(), validUtf16Input.size(), utf32Output.data()); +simdutf_warn_unused size_t convert_valid_utf16be_to_utf32( + const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf16be_to_utf32(std::span valid_utf16_input, + std::span utf32_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16_to_utf32::convert_valid( + valid_utf16_input.data(), valid_utf16_input.size(), + utf32_output.data()); + } else + #endif + { + return convert_valid_utf16be_to_utf32(valid_utf16_input.data(), + valid_utf16_input.size(), + utf32_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -7327,21 +7814,23 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ -simdutf_warn_unused auto utf8_length_from_utf16(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto utf8_length_from_utf16(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16(validUtf16Input.data(), - validUtf16Input.size()); - } else -#endif - { - return utf8_length_from_utf16(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t utf8_length_from_utf16(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf8_length_from_utf16(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf8_length_from_utf16(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Using native endianness; compute the number of bytes that this UTF-16 @@ -7361,22 +7850,24 @@ simdutf_really_inline simdutf_warn_unused * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ -simdutf_warn_unused auto utf8_length_from_utf16_with_replacement(const char16_t* input, size_t length) noexcept - -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_from_utf16_with_replacement( - std::span validUtf16Input) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16_with_replacement(validUtf16Input.data(), - validUtf16Input.size()); - } else -#endif - { - return utf8_length_from_utf16_with_replacement(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused result utf8_length_from_utf16_with_replacement( + const char16_t *input, size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +utf8_length_from_utf16_with_replacement( + std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16_with_replacement< + endianness::NATIVE>(valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf8_length_from_utf16_with_replacement(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-8 @@ -7389,21 +7880,23 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto utf8_length_f * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ -simdutf_warn_unused auto utf8_length_from_utf16le(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 - simdutf_warn_unused auto utf8_length_from_utf16le(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16(validUtf16Input.data(), - validUtf16Input.size()); - } else -#endif - { - return utf8_length_from_utf16le(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t utf8_length_from_utf16le(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t +utf8_length_from_utf16le(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf8_length_from_utf16le(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-8 @@ -7416,20 +7909,23 @@ simdutf_really_inline simdutf_constexpr23 * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-8 */ -simdutf_warn_unused auto utf8_length_from_utf16be(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto utf8_length_from_utf16be(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf8_length_from_utf16(validUtf16Input.data(), validUtf16Input.size()); - } else -#endif - { - return utf8_length_from_utf16be(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t utf8_length_from_utf16be(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf8_length_from_utf16be(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf8_length_from_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf8_length_from_utf16be(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -7446,21 +7942,26 @@ simdutf_really_inline simdutf_warn_unused * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ -simdutf_warn_unused auto convert_utf32_to_utf8(const char32_t* input, size_t length, char* utf8Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf8( - std::span utf32Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf8::convert(utf32Input.data(), utf32Input.size(), utf8Output.data()); - } else -#endif - { - return convert_utf32_to_utf8(utf32Input.data(), utf32Input.size(), reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_utf32_to_utf8(const char32_t *input, + size_t length, + char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf32_to_utf8( + std::span utf32_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf8::convert( + utf32_input.data(), utf32_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf32_to_utf8(utf32_input.data(), utf32_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-8 string and stop on error. @@ -7478,22 +7979,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused auto convert_utf32_to_utf8_with_errors(const char32_t* input, size_t length, - char* utf8Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf8_with_errors( - std::span utf32Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf8::convert_with_errors(utf32Input.data(), utf32Input.size(), utf8Output.data()); - } else -#endif - { - return convert_utf32_to_utf8_with_errors(utf32Input.data(), utf32Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused result convert_utf32_to_utf8_with_errors( + const char32_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf32_to_utf8_with_errors( + std::span utf32_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf8::convert_with_errors( + utf32_input.data(), utf32_input.size(), utf8_output.data()); + } else + #endif + { + return convert_utf32_to_utf8_with_errors( + utf32_input.data(), utf32_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-8 string. @@ -7508,22 +8013,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf32_to_utf8(const char32_t* input, size_t length, char* utf8Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf32_to_utf8( - std::span validUtf32Input, detail::output_span_of_byte_like auto&& utf8Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf8::convert_valid(validUtf32Input.data(), validUtf32Input.size(), utf8Output.data()); - } else -#endif - { - return convert_valid_utf32_to_utf8(validUtf32Input.data(), validUtf32Input.size(), - reinterpret_cast(utf8Output.data())); +simdutf_warn_unused size_t convert_valid_utf32_to_utf8( + const char32_t *input, size_t length, char *utf8_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf32_to_utf8( + std::span valid_utf32_input, + detail::output_span_of_byte_like auto &&utf8_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf8::convert_valid( + valid_utf32_input.data(), valid_utf32_input.size(), utf8_output.data()); + } else + #endif + { + return convert_valid_utf32_to_utf8( + valid_utf32_input.data(), valid_utf32_input.size(), + reinterpret_cast(utf8_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -7541,22 +8050,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ -simdutf_warn_unused auto convert_utf32_to_utf16(const char32_t* input, size_t length, char16_t* utf16Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16( - std::span utf32Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert(utf32Input.data(), utf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf32_to_utf16(utf32Input.data(), utf32Input.size(), utf16Output.data()); +simdutf_warn_unused size_t convert_utf32_to_utf16( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf32_to_utf16(std::span utf32_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert( + utf32_input.data(), utf32_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf32_to_utf16(utf32_input.data(), utf32_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16LE string. @@ -7571,22 +8082,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ -simdutf_warn_unused auto convert_utf32_to_utf16le(const char32_t* input, size_t length, char16_t* utf16Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16le( - std::span utf32Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert(utf32Input.data(), utf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf32_to_utf16le(utf32Input.data(), utf32Input.size(), utf16Output.data()); +simdutf_warn_unused size_t convert_utf32_to_utf16le( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf32_to_utf16le(std::span utf32_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert( + utf32_input.data(), utf32_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf32_to_utf16le(utf32_input.data(), utf32_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -7604,22 +8117,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * @return number of written code units; 0 if input is not a valid UTF-32 string * or if it cannot be represented as Latin1 */ -simdutf_warn_unused auto convert_utf32_to_latin1(const char32_t* input, size_t length, char* latin1Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_latin1( - std::span utf32Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_latin1::convert(utf32Input.data(), utf32Input.size(), latin1Output.data()); - } else -#endif - { - return convert_utf32_to_latin1(utf32Input.data(), utf32Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused size_t convert_utf32_to_latin1( + const char32_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf32_to_latin1( + std::span utf32_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_latin1::convert( + utf32_input.data(), utf32_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf32_to_latin1( + utf32_input.data(), utf32_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into Latin1 string and stop on error. @@ -7638,22 +8155,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * (in the input in code units) if any, or the number of char written if * successful. */ -simdutf_warn_unused auto convert_utf32_to_latin1_with_errors(const char32_t* input, size_t length, - char* latin1Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_latin1_with_errors( - std::span utf32Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_latin1::convert_with_errors(utf32Input.data(), utf32Input.size(), latin1Output.data()); - } else -#endif - { - return convert_utf32_to_latin1_with_errors(utf32Input.data(), utf32Input.size(), - reinterpret_cast(latin1Output.data())); +simdutf_warn_unused result convert_utf32_to_latin1_with_errors( + const char32_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf32_to_latin1_with_errors( + std::span utf32_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_latin1::convert_with_errors( + utf32_input.data(), utf32_input.size(), latin1_output.data()); + } else + #endif + { + return convert_utf32_to_latin1_with_errors( + utf32_input.data(), utf32_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into Latin1 string. @@ -7675,25 +8196,28 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf32_to_latin1(const char32_t* input, size_t length, - char* latin1Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid_utf32_to_latin1( - std::span validUtf32Input, detail::output_span_of_byte_like auto&& latin1Output) noexcept - -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_latin1::convert_valid(detail::constexpr_cast_ptr(validUtf32Input.data()), - validUtf32Input.size(), - detail::constexpr_cast_writeptr(latin1Output.data())); - } -#endif +simdutf_warn_unused size_t convert_valid_utf32_to_latin1( + const char32_t *input, size_t length, char *latin1_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t +convert_valid_utf32_to_latin1( + std::span valid_utf32_input, + detail::output_span_of_byte_like auto &&latin1_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_latin1::convert_valid( + detail::constexpr_cast_ptr(valid_utf32_input.data()), + valid_utf32_input.size(), + detail::constexpr_cast_writeptr(latin1_output.data())); + } + #endif { - return convert_valid_utf32_to_latin1(validUtf32Input.data(), validUtf32Input.size(), - reinterpret_cast(latin1Output.data())); + return convert_valid_utf32_to_latin1( + valid_utf32_input.data(), valid_utf32_input.size(), + reinterpret_cast(latin1_output.data())); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-32 string would require in Latin1 @@ -7707,9 +8231,9 @@ simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto convert_valid * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto latin1_length_from_utf32(size_t length) noexcept - -> size_t { - return length; +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t +latin1_length_from_utf32(size_t length) noexcept { + return length; } /** @@ -7720,9 +8244,9 @@ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto latin1_length * @return the length of the string in 4-byte code units (char32_t) required to * encode the Latin1 string as UTF-32 */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto utf32_length_from_latin1(size_t length) noexcept - -> size_t { - return length; +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t +utf32_length_from_latin1(size_t length) noexcept { + return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -7740,22 +8264,24 @@ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto utf32_length_ * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ -simdutf_warn_unused auto convert_utf32_to_utf16be(const char32_t* input, size_t length, char16_t* utf16Buffer) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16be( - std::span utf32Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert(utf32Input.data(), utf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf32_to_utf16be(utf32Input.data(), utf32Input.size(), utf16Output.data()); +simdutf_warn_unused size_t convert_utf32_to_utf16be( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_utf32_to_utf16be(std::span utf32_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert( + utf32_input.data(), utf32_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf32_to_utf16be(utf32_input.data(), utf32_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-32 string into UTF-16 @@ -7774,22 +8300,24 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused auto convert_utf32_to_utf16_with_errors(const char32_t* input, size_t length, - char16_t* utf16Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16_with_errors( - std::span utf32Input, std::span utf16Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_with_errors(utf32Input.data(), utf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf32_to_utf16_with_errors(utf32Input.data(), utf32Input.size(), utf16Output.data()); +simdutf_warn_unused result convert_utf32_to_utf16_with_errors( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf32_to_utf16_with_errors(std::span utf32_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_with_errors( + utf32_input.data(), utf32_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf32_to_utf16_with_errors( + utf32_input.data(), utf32_input.size(), utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16LE string and stop on error. @@ -7807,22 +8335,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused auto convert_utf32_to_utf16le_with_errors(const char32_t* input, size_t length, - char16_t* utf16Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16le_with_errors( - std::span utf32Input, std::span utf16Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_with_errors(utf32Input.data(), utf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf32_to_utf16le_with_errors(utf32Input.data(), utf32Input.size(), utf16Output.data()); +simdutf_warn_unused result convert_utf32_to_utf16le_with_errors( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf32_to_utf16le_with_errors( + std::span utf32_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_with_errors( + utf32_input.data(), utf32_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf32_to_utf16le_with_errors( + utf32_input.data(), utf32_input.size(), utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16BE string and stop on error. @@ -7840,22 +8371,25 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * (in the input in code units) if any, or the number of char16_t written if * successful. */ -simdutf_warn_unused auto convert_utf32_to_utf16be_with_errors(const char32_t* input, size_t length, - char16_t* utf16Buffer) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32_to_utf16be_with_errors( - std::span utf32Input, std::span utf16Output) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_with_errors(utf32Input.data(), utf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_utf32_to_utf16be_with_errors(utf32Input.data(), utf32Input.size(), utf16Output.data()); +simdutf_warn_unused result convert_utf32_to_utf16be_with_errors( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +convert_utf32_to_utf16be_with_errors( + std::span utf32_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_with_errors( + utf32_input.data(), utf32_input.size(), utf16_output.data()); + } else + #endif + { + return convert_utf32_to_utf16be_with_errors( + utf32_input.data(), utf32_input.size(), utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Using native endianness, convert valid UTF-32 string into a UTF-16 string. @@ -7870,22 +8404,27 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_utf32 * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf32_to_utf16(const char32_t* input, size_t length, - char16_t* utf16Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf32_to_utf16( - std::span validUtf32Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_valid(validUtf32Input.data(), validUtf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_valid_utf32_to_utf16(validUtf32Input.data(), validUtf32Input.size(), utf16Output.data()); +simdutf_warn_unused size_t convert_valid_utf32_to_utf16( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf32_to_utf16(std::span valid_utf32_input, + std::span utf16_output) noexcept { + + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_valid( + valid_utf32_input.data(), valid_utf32_input.size(), + utf16_output.data()); + } else + #endif + { + return convert_valid_utf32_to_utf16(valid_utf32_input.data(), + valid_utf32_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-16LE string. @@ -7900,22 +8439,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf32_to_utf16le(const char32_t* input, size_t length, - char16_t* utf16Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf32_to_utf16le( - std::span validUtf32Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_valid(validUtf32Input.data(), validUtf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_valid_utf32_to_utf16le(validUtf32Input.data(), validUtf32Input.size(), utf16Output.data()); +simdutf_warn_unused size_t convert_valid_utf32_to_utf16le( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf32_to_utf16le(std::span valid_utf32_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_valid( + valid_utf32_input.data(), valid_utf32_input.size(), + utf16_output.data()); + } else + #endif + { + return convert_valid_utf32_to_utf16le(valid_utf32_input.data(), + valid_utf32_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-16BE string. @@ -7930,22 +8473,26 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid * result * @return number of written code units; 0 if conversion is not possible */ -simdutf_warn_unused auto convert_valid_utf32_to_utf16be(const char32_t* input, size_t length, - char16_t* utf16Buffer) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid_utf32_to_utf16be( - std::span validUtf32Input, std::span utf16Output) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32_to_utf16::convert_valid(validUtf32Input.data(), validUtf32Input.size(), - utf16Output.data()); - } else -#endif - { - return convert_valid_utf32_to_utf16be(validUtf32Input.data(), validUtf32Input.size(), utf16Output.data()); +simdutf_warn_unused size_t convert_valid_utf32_to_utf16be( + const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +convert_valid_utf32_to_utf16be(std::span valid_utf32_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32_to_utf16::convert_valid( + valid_utf32_input.data(), valid_utf32_input.size(), + utf16_output.data()); + } else + #endif + { + return convert_valid_utf32_to_utf16be(valid_utf32_input.data(), + valid_utf32_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 @@ -7965,20 +8512,21 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto convert_valid void change_endianness_utf16(const char16_t *input, size_t length, char16_t *output) noexcept; #if SIMDUTF_SPAN -simdutf_really_inline simdutf_constexpr23 void change_endianness_utf16(std::span utf16Input, - std::span utf16Output) noexcept { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - scalar::utf16::change_endianness_utf16(utf16Input.data(), utf16Input.size(), utf16Output.data()); - return; - } else -#endif - { - change_endianness_utf16(utf16Input.data(), utf16Input.size(), utf16Output.data()); - return; +simdutf_really_inline simdutf_constexpr23 void +change_endianness_utf16(std::span utf16_input, + std::span utf16_output) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::change_endianness_utf16( + utf16_input.data(), utf16_input.size(), utf16_output.data()); + } else + #endif + { + return change_endianness_utf16(utf16_input.data(), utf16_input.size(), + utf16_output.data()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -7993,20 +8541,23 @@ simdutf_really_inline simdutf_constexpr23 void change_endianness_utf16(std::span * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-8 */ -simdutf_warn_unused auto utf8_length_from_utf32(const char32_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto utf8_length_from_utf32(std::span validUtf32Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32::utf8_length_from_utf32(validUtf32Input.data(), validUtf32Input.size()); - } else -#endif - { - return utf8_length_from_utf32(validUtf32Input.data(), validUtf32Input.size()); +simdutf_warn_unused size_t utf8_length_from_utf32(const char32_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf8_length_from_utf32(std::span valid_utf32_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32::utf8_length_from_utf32(valid_utf32_input.data(), + valid_utf32_input.size()); + } else + #endif + { + return utf8_length_from_utf32(valid_utf32_input.data(), + valid_utf32_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -8021,20 +8572,23 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-16 */ -simdutf_warn_unused auto utf16_length_from_utf32(const char32_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto utf16_length_from_utf32(std::span validUtf32Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf32::utf16_length_from_utf32(validUtf32Input.data(), validUtf32Input.size()); - } else -#endif - { - return utf16_length_from_utf32(validUtf32Input.data(), validUtf32Input.size()); +simdutf_warn_unused size_t utf16_length_from_utf32(const char32_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf16_length_from_utf32(std::span valid_utf32_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf32::utf16_length_from_utf32(valid_utf32_input.data(), + valid_utf32_input.size()); + } else + #endif + { + return utf16_length_from_utf32(valid_utf32_input.data(), + valid_utf32_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Using native endianness; Compute the number of bytes that this UTF-16 @@ -8051,21 +8605,23 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-32 */ -simdutf_warn_unused auto utf32_length_from_utf16(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto utf32_length_from_utf16(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf32_length_from_utf16(validUtf16Input.data(), - validUtf16Input.size()); - } else -#endif - { - return utf32_length_from_utf16(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t utf32_length_from_utf16(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf32_length_from_utf16(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf32_length_from_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf32_length_from_utf16(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-32 @@ -8082,21 +8638,24 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-32 */ -simdutf_warn_unused auto utf32_length_from_utf16le(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto utf32_length_from_utf16le(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf32_length_from_utf16(validUtf16Input.data(), - validUtf16Input.size()); - } else -#endif - { - return utf32_length_from_utf16le(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t utf32_length_from_utf16le(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf32_length_from_utf16le( + std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf32_length_from_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf32_length_from_utf16le(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-32 @@ -8113,20 +8672,24 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-32 */ -simdutf_warn_unused auto utf32_length_from_utf16be(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto utf32_length_from_utf16be(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::utf32_length_from_utf16(validUtf16Input.data(), validUtf16Input.size()); - } else -#endif - { - return utf32_length_from_utf16be(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t utf32_length_from_utf16be(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +utf32_length_from_utf16be( + std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::utf32_length_from_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return utf32_length_from_utf16be(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 @@ -8144,20 +8707,22 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ -simdutf_warn_unused auto count_utf16(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto count_utf16(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::count_code_points(validUtf16Input.data(), validUtf16Input.size()); - } else -#endif - { - return count_utf16(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t count_utf16(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +count_utf16(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::count_code_points( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return count_utf16(valid_utf16_input.data(), valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Count the number of code points (characters) in the string assuming that @@ -8173,20 +8738,22 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ -simdutf_warn_unused auto count_utf16le(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto count_utf16le(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::count_code_points(validUtf16Input.data(), validUtf16Input.size()); - } else -#endif - { - return count_utf16le(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t count_utf16le(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +count_utf16le(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::count_code_points( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return count_utf16le(valid_utf16_input.data(), valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Count the number of code points (characters) in the string assuming that @@ -8202,20 +8769,22 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ -simdutf_warn_unused auto count_utf16be(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto count_utf16be(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::count_code_points(validUtf16Input.data(), validUtf16Input.size()); - } else -#endif - { - return count_utf16be(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t count_utf16be(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +count_utf16be(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::count_code_points( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return count_utf16be(valid_utf16_input.data(), valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 @@ -8231,20 +8800,23 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in bytes * @return number of code points */ -simdutf_warn_unused auto count_utf8(const char* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto count_utf8(const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::count_code_points(validUtf8Input.data(), validUtf8Input.size()); - } else -#endif - { - return count_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); +simdutf_warn_unused size_t count_utf8(const char *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf8( + const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::count_code_points(valid_utf8_input.data(), + valid_utf8_input.size()); + } else + #endif + { + return count_utf8(reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Given a valid UTF-8 string having a possibly truncated last character, @@ -8260,20 +8832,24 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in bytes * @return the length of the string in bytes, possibly shorter by 1 to 3 bytes */ -simdutf_warn_unused auto trim_partial_utf8(const char* input, size_t length) -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto trim_partial_utf8( - const detail::input_span_of_byte_like auto& validUtf8Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf8::trim_partial_utf8(validUtf8Input.data(), validUtf8Input.size()); - } else -#endif - { - return trim_partial_utf8(reinterpret_cast(validUtf8Input.data()), validUtf8Input.size()); +simdutf_warn_unused size_t trim_partial_utf8(const char *input, size_t length); + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +trim_partial_utf8( + const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf8::trim_partial_utf8(valid_utf8_input.data(), + valid_utf8_input.size()); + } else + #endif + { + return trim_partial_utf8( + reinterpret_cast(valid_utf8_input.data()), + valid_utf8_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_UTF16 @@ -8291,20 +8867,23 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto trim_partial_ * @param length the length of the string in bytes * @return the length of the string in bytes, possibly shorter by 1 unit */ -simdutf_warn_unused auto trim_partial_utf16be(const char16_t* input, size_t length) -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto trim_partial_utf16be(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::trim_partial_utf16(validUtf16Input.data(), validUtf16Input.size()); - } else -#endif - { - return trim_partial_utf16be(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t trim_partial_utf16be(const char16_t *input, + size_t length); + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +trim_partial_utf16be(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::trim_partial_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return trim_partial_utf16be(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Given a valid UTF-16LE string having a possibly truncated last character, @@ -8320,20 +8899,23 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in bytes * @return the length of the string in unit, possibly shorter by 1 unit */ -simdutf_warn_unused auto trim_partial_utf16le(const char16_t* input, size_t length) -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto trim_partial_utf16le(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::trim_partial_utf16(validUtf16Input.data(), validUtf16Input.size()); - } else -#endif - { - return trim_partial_utf16le(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t trim_partial_utf16le(const char16_t *input, + size_t length); + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +trim_partial_utf16le(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::trim_partial_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return trim_partial_utf16le(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Given a valid UTF-16 string having a possibly truncated last character, @@ -8349,20 +8931,23 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the string in bytes * @return the length of the string in unit, possibly shorter by 1 unit */ -simdutf_warn_unused auto trim_partial_utf16(const char16_t* input, size_t length) -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto trim_partial_utf16(std::span validUtf16Input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::utf16::trim_partial_utf16(validUtf16Input.data(), validUtf16Input.size()); - } else -#endif - { - return trim_partial_utf16(validUtf16Input.data(), validUtf16Input.size()); +simdutf_warn_unused size_t trim_partial_utf16(const char16_t *input, + size_t length); + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +trim_partial_utf16(std::span valid_utf16_input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::utf16::trim_partial_utf16( + valid_utf16_input.data(), valid_utf16_input.size()); + } else + #endif + { + return trim_partial_utf16(valid_utf16_input.data(), + valid_utf16_input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_BASE64 || SIMDUTF_FEATURE_UTF16 || \ @@ -8378,12 +8963,16 @@ simdutf_really_inline simdutf_warn_unused // ASCII spaces are ' ', '\t', '\n', '\r', '\f' // garbage characters are characters that are not part of the base64 alphabet // nor ASCII spaces. -constexpr uint64_t base64ReversePadding = 2; /* modifier for base64_default and base64_url */ +constexpr uint64_t base64_reverse_padding = + 2; /* modifier for base64_default and base64_url */ enum base64_options : uint64_t { base64_default = 0, /* standard base64 format (with padding) */ base64_url = 1, /* base64url format (no padding) */ - base64_default_no_padding = base64_default | base64ReversePadding, /* standard base64 format without padding */ - base64_url_with_padding = base64_url | base64ReversePadding, /* base64url with padding */ + base64_default_no_padding = + base64_default | + base64_reverse_padding, /* standard base64 format without padding */ + base64_url_with_padding = + base64_url | base64_reverse_padding, /* base64url with padding */ base64_default_accept_garbage = 4, /* standard base64 format accepting garbage characters, the input stops with the first '=' if any */ @@ -8411,14 +9000,16 @@ enum last_chunk_handling_options : uint64_t { 3 /* only decode full blocks (4 base64 characters, no padding) */ }; -simdutf_constexpr23 auto is_partial(last_chunk_handling_options options) -> bool { - return (options == stop_before_partial) || (options == only_full_chunks); +inline simdutf_constexpr23 bool +is_partial(last_chunk_handling_options options) { + return (options == stop_before_partial) || (options == only_full_chunks); } namespace detail { -simdutf_warn_unused auto find(const char* start, const char* end, char character) noexcept -> const char*; -simdutf_warn_unused auto find(const char16_t* start, const char16_t* end, char16_t character) noexcept -> const - char16_t*; +simdutf_warn_unused const char *find(const char *start, const char *end, + char character) noexcept; +simdutf_warn_unused const char16_t * +find(const char16_t *start, const char16_t *end, char16_t character) noexcept; } // namespace detail /** @@ -8431,34 +9022,29 @@ simdutf_warn_unused auto find(const char16_t* start, const char16_t* end, char16 * or a pointer to the end of the string if the character is not found. * */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto find(const char* start, const char* end, - char character) noexcept -> const char* { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - for (; start != end; ++start) { - if (*start == character) { - return start; - } - } - return end; - } else -#endif - { +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char * +find(const char *start, const char *end, char character) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + for (; start != end; ++start) + if (*start == character) + return start; + return end; + } else + #endif + { return detail::find(start, end, character); } } -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto find(const char16_t* start, const char16_t* end, - char16_t character) noexcept -> const - char16_t* { +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char16_t * +find(const char16_t *start, const char16_t *end, char16_t character) noexcept { // implementation note: this is repeated instead of a template, to ensure // the api is still a function and compiles without concepts #if SIMDUTF_CPLUSPLUS23 if consteval { - for (; start != end; ++start) { - if (*start == character) { - return start; - } - } + for (; start != end; ++start) + if (*start == character) + return start; return end; } else #endif @@ -8475,8 +9061,8 @@ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto find(const ch namespace simdutf { namespace { - -namespace tables::base64 { +namespace tables { +namespace base64 { namespace base64_default { constexpr char e0[256] = { @@ -9138,143 +9724,220 @@ constexpr uint32_t d3[256] = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; } // namespace base64_default_or_url -constexpr uint64_t thintableEpi8[256] = { - 0x0706050403020100, 0x0007060504030201, 0x0007060504030200, 0x0000070605040302, 0x0007060504030100, - 0x0000070605040301, 0x0000070605040300, 0x0000000706050403, 0x0007060504020100, 0x0000070605040201, - 0x0000070605040200, 0x0000000706050402, 0x0000070605040100, 0x0000000706050401, 0x0000000706050400, - 0x0000000007060504, 0x0007060503020100, 0x0000070605030201, 0x0000070605030200, 0x0000000706050302, - 0x0000070605030100, 0x0000000706050301, 0x0000000706050300, 0x0000000007060503, 0x0000070605020100, - 0x0000000706050201, 0x0000000706050200, 0x0000000007060502, 0x0000000706050100, 0x0000000007060501, - 0x0000000007060500, 0x0000000000070605, 0x0007060403020100, 0x0000070604030201, 0x0000070604030200, - 0x0000000706040302, 0x0000070604030100, 0x0000000706040301, 0x0000000706040300, 0x0000000007060403, - 0x0000070604020100, 0x0000000706040201, 0x0000000706040200, 0x0000000007060402, 0x0000000706040100, - 0x0000000007060401, 0x0000000007060400, 0x0000000000070604, 0x0000070603020100, 0x0000000706030201, - 0x0000000706030200, 0x0000000007060302, 0x0000000706030100, 0x0000000007060301, 0x0000000007060300, - 0x0000000000070603, 0x0000000706020100, 0x0000000007060201, 0x0000000007060200, 0x0000000000070602, - 0x0000000007060100, 0x0000000000070601, 0x0000000000070600, 0x0000000000000706, 0x0007050403020100, - 0x0000070504030201, 0x0000070504030200, 0x0000000705040302, 0x0000070504030100, 0x0000000705040301, - 0x0000000705040300, 0x0000000007050403, 0x0000070504020100, 0x0000000705040201, 0x0000000705040200, - 0x0000000007050402, 0x0000000705040100, 0x0000000007050401, 0x0000000007050400, 0x0000000000070504, - 0x0000070503020100, 0x0000000705030201, 0x0000000705030200, 0x0000000007050302, 0x0000000705030100, - 0x0000000007050301, 0x0000000007050300, 0x0000000000070503, 0x0000000705020100, 0x0000000007050201, - 0x0000000007050200, 0x0000000000070502, 0x0000000007050100, 0x0000000000070501, 0x0000000000070500, - 0x0000000000000705, 0x0000070403020100, 0x0000000704030201, 0x0000000704030200, 0x0000000007040302, - 0x0000000704030100, 0x0000000007040301, 0x0000000007040300, 0x0000000000070403, 0x0000000704020100, - 0x0000000007040201, 0x0000000007040200, 0x0000000000070402, 0x0000000007040100, 0x0000000000070401, - 0x0000000000070400, 0x0000000000000704, 0x0000000703020100, 0x0000000007030201, 0x0000000007030200, - 0x0000000000070302, 0x0000000007030100, 0x0000000000070301, 0x0000000000070300, 0x0000000000000703, - 0x0000000007020100, 0x0000000000070201, 0x0000000000070200, 0x0000000000000702, 0x0000000000070100, - 0x0000000000000701, 0x0000000000000700, 0x0000000000000007, 0x0006050403020100, 0x0000060504030201, - 0x0000060504030200, 0x0000000605040302, 0x0000060504030100, 0x0000000605040301, 0x0000000605040300, - 0x0000000006050403, 0x0000060504020100, 0x0000000605040201, 0x0000000605040200, 0x0000000006050402, - 0x0000000605040100, 0x0000000006050401, 0x0000000006050400, 0x0000000000060504, 0x0000060503020100, - 0x0000000605030201, 0x0000000605030200, 0x0000000006050302, 0x0000000605030100, 0x0000000006050301, - 0x0000000006050300, 0x0000000000060503, 0x0000000605020100, 0x0000000006050201, 0x0000000006050200, - 0x0000000000060502, 0x0000000006050100, 0x0000000000060501, 0x0000000000060500, 0x0000000000000605, - 0x0000060403020100, 0x0000000604030201, 0x0000000604030200, 0x0000000006040302, 0x0000000604030100, - 0x0000000006040301, 0x0000000006040300, 0x0000000000060403, 0x0000000604020100, 0x0000000006040201, - 0x0000000006040200, 0x0000000000060402, 0x0000000006040100, 0x0000000000060401, 0x0000000000060400, - 0x0000000000000604, 0x0000000603020100, 0x0000000006030201, 0x0000000006030200, 0x0000000000060302, - 0x0000000006030100, 0x0000000000060301, 0x0000000000060300, 0x0000000000000603, 0x0000000006020100, - 0x0000000000060201, 0x0000000000060200, 0x0000000000000602, 0x0000000000060100, 0x0000000000000601, - 0x0000000000000600, 0x0000000000000006, 0x0000050403020100, 0x0000000504030201, 0x0000000504030200, - 0x0000000005040302, 0x0000000504030100, 0x0000000005040301, 0x0000000005040300, 0x0000000000050403, - 0x0000000504020100, 0x0000000005040201, 0x0000000005040200, 0x0000000000050402, 0x0000000005040100, - 0x0000000000050401, 0x0000000000050400, 0x0000000000000504, 0x0000000503020100, 0x0000000005030201, - 0x0000000005030200, 0x0000000000050302, 0x0000000005030100, 0x0000000000050301, 0x0000000000050300, - 0x0000000000000503, 0x0000000005020100, 0x0000000000050201, 0x0000000000050200, 0x0000000000000502, - 0x0000000000050100, 0x0000000000000501, 0x0000000000000500, 0x0000000000000005, 0x0000000403020100, - 0x0000000004030201, 0x0000000004030200, 0x0000000000040302, 0x0000000004030100, 0x0000000000040301, - 0x0000000000040300, 0x0000000000000403, 0x0000000004020100, 0x0000000000040201, 0x0000000000040200, - 0x0000000000000402, 0x0000000000040100, 0x0000000000000401, 0x0000000000000400, 0x0000000000000004, - 0x0000000003020100, 0x0000000000030201, 0x0000000000030200, 0x0000000000000302, 0x0000000000030100, - 0x0000000000000301, 0x0000000000000300, 0x0000000000000003, 0x0000000000020100, 0x0000000000000201, - 0x0000000000000200, 0x0000000000000002, 0x0000000000000100, 0x0000000000000001, 0x0000000000000000, +constexpr uint64_t thintable_epi8[256] = { + 0x0706050403020100, 0x0007060504030201, 0x0007060504030200, + 0x0000070605040302, 0x0007060504030100, 0x0000070605040301, + 0x0000070605040300, 0x0000000706050403, 0x0007060504020100, + 0x0000070605040201, 0x0000070605040200, 0x0000000706050402, + 0x0000070605040100, 0x0000000706050401, 0x0000000706050400, + 0x0000000007060504, 0x0007060503020100, 0x0000070605030201, + 0x0000070605030200, 0x0000000706050302, 0x0000070605030100, + 0x0000000706050301, 0x0000000706050300, 0x0000000007060503, + 0x0000070605020100, 0x0000000706050201, 0x0000000706050200, + 0x0000000007060502, 0x0000000706050100, 0x0000000007060501, + 0x0000000007060500, 0x0000000000070605, 0x0007060403020100, + 0x0000070604030201, 0x0000070604030200, 0x0000000706040302, + 0x0000070604030100, 0x0000000706040301, 0x0000000706040300, + 0x0000000007060403, 0x0000070604020100, 0x0000000706040201, + 0x0000000706040200, 0x0000000007060402, 0x0000000706040100, + 0x0000000007060401, 0x0000000007060400, 0x0000000000070604, + 0x0000070603020100, 0x0000000706030201, 0x0000000706030200, + 0x0000000007060302, 0x0000000706030100, 0x0000000007060301, + 0x0000000007060300, 0x0000000000070603, 0x0000000706020100, + 0x0000000007060201, 0x0000000007060200, 0x0000000000070602, + 0x0000000007060100, 0x0000000000070601, 0x0000000000070600, + 0x0000000000000706, 0x0007050403020100, 0x0000070504030201, + 0x0000070504030200, 0x0000000705040302, 0x0000070504030100, + 0x0000000705040301, 0x0000000705040300, 0x0000000007050403, + 0x0000070504020100, 0x0000000705040201, 0x0000000705040200, + 0x0000000007050402, 0x0000000705040100, 0x0000000007050401, + 0x0000000007050400, 0x0000000000070504, 0x0000070503020100, + 0x0000000705030201, 0x0000000705030200, 0x0000000007050302, + 0x0000000705030100, 0x0000000007050301, 0x0000000007050300, + 0x0000000000070503, 0x0000000705020100, 0x0000000007050201, + 0x0000000007050200, 0x0000000000070502, 0x0000000007050100, + 0x0000000000070501, 0x0000000000070500, 0x0000000000000705, + 0x0000070403020100, 0x0000000704030201, 0x0000000704030200, + 0x0000000007040302, 0x0000000704030100, 0x0000000007040301, + 0x0000000007040300, 0x0000000000070403, 0x0000000704020100, + 0x0000000007040201, 0x0000000007040200, 0x0000000000070402, + 0x0000000007040100, 0x0000000000070401, 0x0000000000070400, + 0x0000000000000704, 0x0000000703020100, 0x0000000007030201, + 0x0000000007030200, 0x0000000000070302, 0x0000000007030100, + 0x0000000000070301, 0x0000000000070300, 0x0000000000000703, + 0x0000000007020100, 0x0000000000070201, 0x0000000000070200, + 0x0000000000000702, 0x0000000000070100, 0x0000000000000701, + 0x0000000000000700, 0x0000000000000007, 0x0006050403020100, + 0x0000060504030201, 0x0000060504030200, 0x0000000605040302, + 0x0000060504030100, 0x0000000605040301, 0x0000000605040300, + 0x0000000006050403, 0x0000060504020100, 0x0000000605040201, + 0x0000000605040200, 0x0000000006050402, 0x0000000605040100, + 0x0000000006050401, 0x0000000006050400, 0x0000000000060504, + 0x0000060503020100, 0x0000000605030201, 0x0000000605030200, + 0x0000000006050302, 0x0000000605030100, 0x0000000006050301, + 0x0000000006050300, 0x0000000000060503, 0x0000000605020100, + 0x0000000006050201, 0x0000000006050200, 0x0000000000060502, + 0x0000000006050100, 0x0000000000060501, 0x0000000000060500, + 0x0000000000000605, 0x0000060403020100, 0x0000000604030201, + 0x0000000604030200, 0x0000000006040302, 0x0000000604030100, + 0x0000000006040301, 0x0000000006040300, 0x0000000000060403, + 0x0000000604020100, 0x0000000006040201, 0x0000000006040200, + 0x0000000000060402, 0x0000000006040100, 0x0000000000060401, + 0x0000000000060400, 0x0000000000000604, 0x0000000603020100, + 0x0000000006030201, 0x0000000006030200, 0x0000000000060302, + 0x0000000006030100, 0x0000000000060301, 0x0000000000060300, + 0x0000000000000603, 0x0000000006020100, 0x0000000000060201, + 0x0000000000060200, 0x0000000000000602, 0x0000000000060100, + 0x0000000000000601, 0x0000000000000600, 0x0000000000000006, + 0x0000050403020100, 0x0000000504030201, 0x0000000504030200, + 0x0000000005040302, 0x0000000504030100, 0x0000000005040301, + 0x0000000005040300, 0x0000000000050403, 0x0000000504020100, + 0x0000000005040201, 0x0000000005040200, 0x0000000000050402, + 0x0000000005040100, 0x0000000000050401, 0x0000000000050400, + 0x0000000000000504, 0x0000000503020100, 0x0000000005030201, + 0x0000000005030200, 0x0000000000050302, 0x0000000005030100, + 0x0000000000050301, 0x0000000000050300, 0x0000000000000503, + 0x0000000005020100, 0x0000000000050201, 0x0000000000050200, + 0x0000000000000502, 0x0000000000050100, 0x0000000000000501, + 0x0000000000000500, 0x0000000000000005, 0x0000000403020100, + 0x0000000004030201, 0x0000000004030200, 0x0000000000040302, + 0x0000000004030100, 0x0000000000040301, 0x0000000000040300, + 0x0000000000000403, 0x0000000004020100, 0x0000000000040201, + 0x0000000000040200, 0x0000000000000402, 0x0000000000040100, + 0x0000000000000401, 0x0000000000000400, 0x0000000000000004, + 0x0000000003020100, 0x0000000000030201, 0x0000000000030200, + 0x0000000000000302, 0x0000000000030100, 0x0000000000000301, + 0x0000000000000300, 0x0000000000000003, 0x0000000000020100, + 0x0000000000000201, 0x0000000000000200, 0x0000000000000002, + 0x0000000000000100, 0x0000000000000001, 0x0000000000000000, 0x0000000000000000, }; -constexpr uint8_t pshufbCombineTable[272] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +constexpr uint8_t pshufb_combine_table[272] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x01, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; -constexpr unsigned char bitsSetTable256mul2[256] = { - 0, 2, 2, 4, 2, 4, 4, 6, 2, 4, 4, 6, 4, 6, 6, 8, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, - 8, 8, 10, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, - 8, 10, 8, 10, 10, 12, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, - 10, 6, 8, 8, 10, 8, 10, 10, 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 6, 8, 8, 10, - 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, - 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, - 10, 12, 6, 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, - 10, 8, 10, 10, 12, 6, 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 6, 8, 8, 10, 8, 10, 10, 12, - 8, 10, 10, 12, 10, 12, 12, 14, 8, 10, 10, 12, 10, 12, 12, 14, 10, 12, 12, 14, 12, 14, 14, 16}; - -constexpr uint8_t toBase64Value[] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, - 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; - -constexpr uint8_t toBase64UrlValue[] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 62, 255, 255, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; - -constexpr uint8_t toBase64DefaultOrUrlValue[] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, - 255, 62, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; - -static_assert(sizeof(toBase64Value) == 256, "to_base64_value must have 256 elements"); -static_assert(sizeof(toBase64UrlValue) == 256, "to_base64_url_value must have 256 elements"); -static_assert(toBase64Value[static_cast(' ')] == 64, "space must be == 64 in to_base64_value"); -static_assert(toBase64UrlValue[static_cast(' ')] == 64, "space must be == 64 in to_base64_url_value"); -static_assert(toBase64Value[static_cast('\t')] == 64, "tab must be == 64 in to_base64_value"); -static_assert(toBase64UrlValue[static_cast('\t')] == 64, "tab must be == 64 in to_base64_url_value"); -static_assert(toBase64Value[static_cast('\r')] == 64, "cr must be == 64 in to_base64_value"); -static_assert(toBase64UrlValue[static_cast('\r')] == 64, "cr must be == 64 in to_base64_url_value"); -static_assert(toBase64Value[static_cast('\n')] == 64, "lf must be == 64 in to_base64_value"); -static_assert(toBase64UrlValue[static_cast('\n')] == 64, "lf must be == 64 in to_base64_url_value"); -static_assert(toBase64Value[static_cast('\f')] == 64, "ff must be == 64 in to_base64_value"); -static_assert(toBase64UrlValue[static_cast('\f')] == 64, "ff must be == 64 in to_base64_url_value"); -static_assert(toBase64Value[static_cast('+')] == 62, "+ must be == 62 in to_base64_value"); -static_assert(toBase64UrlValue[static_cast('-')] == 62, "- must be == 62 in to_base64_url_value"); -static_assert(toBase64Value[static_cast('/')] == 63, "/ must be == 63 in to_base64_value"); -static_assert(toBase64UrlValue[static_cast('_')] == 63, "_ must be == 63 in to_base64_url_value"); -} // namespace tables::base64 - +constexpr unsigned char BitsSetTable256mul2[256] = { + 0, 2, 2, 4, 2, 4, 4, 6, 2, 4, 4, 6, 4, 6, 6, 8, 2, 4, 4, + 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 2, 4, 4, 6, 4, 6, + 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, 6, + 8, 8, 10, 8, 10, 10, 12, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, + 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, + 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 6, 8, + 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 2, 4, 4, 6, 4, + 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, + 6, 8, 8, 10, 8, 10, 10, 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, + 10, 8, 10, 10, 12, 6, 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, + 12, 14, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 6, + 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 6, 8, 8, 10, + 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 8, 10, 10, 12, 10, 12, 12, + 14, 10, 12, 12, 14, 12, 14, 14, 16}; + +constexpr uint8_t to_base64_value[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, + 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255}; + +constexpr uint8_t to_base64_url_value[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 62, 255, 255, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255}; + +constexpr uint8_t to_base64_default_or_url_value[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, + 62, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255}; + +static_assert(sizeof(to_base64_value) == 256, + "to_base64_value must have 256 elements"); +static_assert(sizeof(to_base64_url_value) == 256, + "to_base64_url_value must have 256 elements"); +static_assert(to_base64_value[uint8_t(' ')] == 64, + "space must be == 64 in to_base64_value"); +static_assert(to_base64_url_value[uint8_t(' ')] == 64, + "space must be == 64 in to_base64_url_value"); +static_assert(to_base64_value[uint8_t('\t')] == 64, + "tab must be == 64 in to_base64_value"); +static_assert(to_base64_url_value[uint8_t('\t')] == 64, + "tab must be == 64 in to_base64_url_value"); +static_assert(to_base64_value[uint8_t('\r')] == 64, + "cr must be == 64 in to_base64_value"); +static_assert(to_base64_url_value[uint8_t('\r')] == 64, + "cr must be == 64 in to_base64_url_value"); +static_assert(to_base64_value[uint8_t('\n')] == 64, + "lf must be == 64 in to_base64_value"); +static_assert(to_base64_url_value[uint8_t('\n')] == 64, + "lf must be == 64 in to_base64_url_value"); +static_assert(to_base64_value[uint8_t('\f')] == 64, + "ff must be == 64 in to_base64_value"); +static_assert(to_base64_url_value[uint8_t('\f')] == 64, + "ff must be == 64 in to_base64_url_value"); +static_assert(to_base64_value[uint8_t('+')] == 62, + "+ must be == 62 in to_base64_value"); +static_assert(to_base64_url_value[uint8_t('-')] == 62, + "- must be == 62 in to_base64_url_value"); +static_assert(to_base64_value[uint8_t('/')] == 63, + "/ must be == 63 in to_base64_value"); +static_assert(to_base64_url_value[uint8_t('_')] == 63, + "_ must be == 63 in to_base64_url_value"); +} // namespace base64 +} // namespace tables } // unnamed namespace } // namespace simdutf @@ -9289,69 +9952,89 @@ static_assert(toBase64UrlValue[static_cast('_')] == 63, "_ must be == 6 #include #include -namespace simdutf::scalar { +namespace simdutf { +namespace scalar { namespace { namespace base64 { // This function is not expected to be fast. Do not use in long loops. // In most instances you should be using is_ignorable. -template auto is_ascii_white_space(char_type c) -> bool { - return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'; +template bool is_ascii_white_space(char_type c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'; } -template simdutf_constexpr23 auto is_eight_byte(char_type c) -> bool { - if constexpr (sizeof(char_type) == 1) { - return true; - } - return uint8_t(c) == c; -} - -template simdutf_constexpr23 auto is_ignorable(char_type c, simdutf::base64_options options) -> bool { - const uint8_t* toBase64 = (options & base64_default_or_url) - ? tables::base64::toBase64DefaultOrUrlValue - : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); - const bool ignoreGarbage = (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - uint8_t code = toBase64[uint8_t(c)]; - if (is_eight_byte(c) && code <= 63) { - return false; - } - if (is_eight_byte(c) && code == 64) { - return true; - } - return ignoreGarbage; +template simdutf_constexpr23 bool is_eight_byte(char_type c) { + if constexpr (sizeof(char_type) == 1) { + return true; + } + return uint8_t(c) == c; +} + +template +simdutf_constexpr23 bool is_ignorable(char_type c, + simdutf::base64_options options) { + const uint8_t *to_base64 = + (options & base64_default_or_url) + ? tables::base64::to_base64_default_or_url_value + : ((options & base64_url) ? tables::base64::to_base64_url_value + : tables::base64::to_base64_value); + const bool ignore_garbage = + (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + uint8_t code = to_base64[uint8_t(c)]; + if (is_eight_byte(c) && code <= 63) { + return false; + } + if (is_eight_byte(c) && code == 64) { + return true; + } + return ignore_garbage; } -template simdutf_constexpr23 auto is_base64(char_type c, simdutf::base64_options options) -> bool { - const uint8_t* toBase64 = (options & base64_default_or_url) - ? tables::base64::toBase64DefaultOrUrlValue - : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); - uint8_t code = toBase64[uint8_t(c)]; - return static_cast(is_eight_byte(c) && code <= 63); +template +simdutf_constexpr23 bool is_base64(char_type c, + simdutf::base64_options options) { + const uint8_t *to_base64 = + (options & base64_default_or_url) + ? tables::base64::to_base64_default_or_url_value + : ((options & base64_url) ? tables::base64::to_base64_url_value + : tables::base64::to_base64_value); + uint8_t code = to_base64[uint8_t(c)]; + if (is_eight_byte(c) && code <= 63) { + return true; + } + return false; } template -simdutf_constexpr23 auto is_base64_or_padding(char_type c, simdutf::base64_options options) -> bool { - const uint8_t* toBase64 = (options & base64_default_or_url) - ? tables::base64::toBase64DefaultOrUrlValue - : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); - if (c == '=') { - return true; - } - uint8_t code = toBase64[uint8_t(c)]; - return static_cast(is_eight_byte(c) && code <= 63); +simdutf_constexpr23 bool is_base64_or_padding(char_type c, + simdutf::base64_options options) { + const uint8_t *to_base64 = + (options & base64_default_or_url) + ? tables::base64::to_base64_default_or_url_value + : ((options & base64_url) ? tables::base64::to_base64_url_value + : tables::base64::to_base64_value); + if (c == '=') { + return true; + } + uint8_t code = to_base64[uint8_t(c)]; + if (is_eight_byte(c) && code <= 63) { + return true; + } + return false; } -template auto is_ignorable_or_padding(char_type c, simdutf::base64_options options) -> bool { - return is_ignorable(c, options) || c == '='; +template +bool is_ignorable_or_padding(char_type c, simdutf::base64_options options) { + return is_ignorable(c, options) || c == '='; } struct reduced_input { size_t equalsigns; // number of padding characters '=', typically 0, 1, 2. size_t equallocation; // location of the first padding character if any size_t srclen; // length of the input buffer before padding - size_t fullInputLength; // length of the input buffer with padding but - // without ignorable characters + size_t full_input_length; // length of the input buffer with padding but + // without ignorable characters }; // find the end of the base64 input buffer @@ -9360,61 +10043,60 @@ struct reduced_input { // and the length of the input buffer with padding. The input buffer is not // modified. The function assumes that there are at most two padding characters. template -simdutf_constexpr23 auto find_end(const char_type* src, size_t srclen, simdutf::base64_options options) - -> reduced_input { - const uint8_t* toBase64 = (options & base64_default_or_url) - ? tables::base64::toBase64DefaultOrUrlValue - : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); - const bool ignoreGarbage = (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - - size_t equalsigns = 0; - // We intentionally include trailing spaces in the full input length. - // See https://github.com/simdutf/simdutf/issues/824 - size_t fullInputLength = srclen; +simdutf_constexpr23 reduced_input find_end(const char_type *src, size_t srclen, + simdutf::base64_options options) { + const uint8_t *to_base64 = + (options & base64_default_or_url) + ? tables::base64::to_base64_default_or_url_value + : ((options & base64_url) ? tables::base64::to_base64_url_value + : tables::base64::to_base64_value); + const bool ignore_garbage = + (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + + size_t equalsigns = 0; + // We intentionally include trailing spaces in the full input length. + // See https://github.com/simdutf/simdutf/issues/824 + size_t full_input_length = srclen; + // skip trailing spaces + while (!ignore_garbage && srclen > 0 && + scalar::base64::is_eight_byte(src[srclen - 1]) && + to_base64[uint8_t(src[srclen - 1])] == 64) { + srclen--; + } + size_t equallocation = + srclen; // location of the first padding character if any + if (ignore_garbage) { + // Technically, we don't need to find the first padding character, we can + // just change our algorithms, but it adds substantial complexity. + auto it = simdutf::find(src, src + srclen, '='); + if (it != src + srclen) { + equallocation = it - src; + equalsigns = 1; + srclen = equallocation; + full_input_length = equallocation + 1; + } + return {equalsigns, equallocation, srclen, full_input_length}; + } + if (!ignore_garbage && srclen > 0 && src[srclen - 1] == '=') { + // This is the last '=' sign. + equallocation = srclen - 1; + srclen--; + equalsigns = 1; // skip trailing spaces - while (!ignoreGarbage && srclen > 0 && scalar::base64::is_eight_byte(src[srclen - 1]) && - toBase64[uint8_t(src[srclen - 1])] == 64) { - srclen--; - } - size_t equallocation = srclen; // location of the first padding character if any - if (ignoreGarbage) { - // Technically, we don't need to find the first padding character, we can - // just change our algorithms, but it adds substantial complexity. - auto it = simdutf::find(src, src + srclen, '='); - if (it != src + srclen) { - equallocation = it - src; - equalsigns = 1; - srclen = equallocation; - fullInputLength = equallocation + 1; - } - return {.equalsigns = equalsigns, - .equallocation = equallocation, - .srclen = srclen, - .full_input_length = fullInputLength}; + while (srclen > 0 && scalar::base64::is_eight_byte(src[srclen - 1]) && + to_base64[uint8_t(src[srclen - 1])] == 64) { + srclen--; } - if (!ignoreGarbage && srclen > 0 && src[srclen - 1] == '=') { - // This is the last '=' sign. - equallocation = srclen - 1; - srclen--; - equalsigns = 1; - // skip trailing spaces - while (srclen > 0 && scalar::base64::is_eight_byte(src[srclen - 1]) && - toBase64[uint8_t(src[srclen - 1])] == 64) { - srclen--; - } - if (srclen > 0 && src[srclen - 1] == '=') { - // This is the second '=' sign. - equallocation = srclen - 1; - srclen--; - equalsigns = 2; - } + if (srclen > 0 && src[srclen - 1] == '=') { + // This is the second '=' sign. + equallocation = srclen - 1; + srclen--; + equalsigns = 2; } - return {.equalsigns = equalsigns, - .equallocation = equallocation, - .srclen = srclen, - .full_input_length = fullInputLength}; + } + return {equalsigns, equallocation, srclen, full_input_length}; } // Returns true upon success. The destination buffer must be large enough. @@ -9422,57 +10104,70 @@ simdutf_constexpr23 auto find_end(const char_type* src, size_t srclen, simdutf:: // if check_capacity is true, it will check that the destination buffer is // large enough. If it is not, it will return OUTPUT_BUFFER_TOO_SMALL. template -simdutf_constexpr23 auto base64_tail_decode_impl(char* dst, size_t outlen, const char_type* src, size_t length, - size_t padding_characters, // number of padding characters - // '=', typically 0, 1, 2. - base64_options options, last_chunk_handling_options last_chunk_options) - -> full_result { - char* dstend = dst + outlen; - (void)dstend; - // This looks like 10 branches, but we expect the compiler to resolve this to - // two branches (easily predicted): - const uint8_t* toBase64 = (options & base64_default_or_url) - ? tables::base64::toBase64DefaultOrUrlValue - : ((options & base64_url) ? tables::base64::toBase64UrlValue : tables::base64::toBase64Value); - const uint32_t* d0 = (options & base64_default_or_url) - ? tables::base64::base64_default_or_url::d0 - : ((options & base64_url) ? tables::base64::base64_url::d0 : tables::base64::base64_default::d0); - const uint32_t* d1 = (options & base64_default_or_url) - ? tables::base64::base64_default_or_url::d1 - : ((options & base64_url) ? tables::base64::base64_url::d1 : tables::base64::base64_default::d1); - const uint32_t* d2 = (options & base64_default_or_url) - ? tables::base64::base64_default_or_url::d2 - : ((options & base64_url) ? tables::base64::base64_url::d2 : tables::base64::base64_default::d2); - const uint32_t* d3 = (options & base64_default_or_url) - ? tables::base64::base64_default_or_url::d3 - : ((options & base64_url) ? tables::base64::base64_url::d3 : tables::base64::base64_default::d3); - const bool ignore_garbage = (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - - const char_type* srcend = src + length; - const char_type* srcinit = src; - const char* dstinit = dst; - - uint32_t x = 0; - size_t idx = 0; - uint8_t buffer[4]; - while (true) { - while (srcend - src >= 4 && is_eight_byte(src[0]) && is_eight_byte(src[1]) && is_eight_byte(src[2]) && - is_eight_byte(src[3]) && - (x = d0[uint8_t(src[0])] | d1[uint8_t(src[1])] | d2[uint8_t(src[2])] | d3[uint8_t(src[3])]) < - 0x01FFFFFF) { - if (check_capacity && dstend - dst < 3) { - return {OUTPUT_BUFFER_TOO_SMALL, size_t(src - srcinit), static_cast(dst - dstinit)}; - } - *dst++ = static_cast(x & 0xFF); - *dst++ = static_cast((x >> 8) & 0xFF); - *dst++ = static_cast((x >> 16) & 0xFF); - src += 4; - } - const char_type* srccur = src; - idx = 0; - // we need at least four characters. +simdutf_constexpr23 full_result base64_tail_decode_impl( + char *dst, size_t outlen, const char_type *src, size_t length, + size_t padding_characters, // number of padding characters + // '=', typically 0, 1, 2. + base64_options options, last_chunk_handling_options last_chunk_options) { + char *dstend = dst + outlen; + (void)dstend; + // This looks like 10 branches, but we expect the compiler to resolve this to + // two branches (easily predicted): + const uint8_t *to_base64 = + (options & base64_default_or_url) + ? tables::base64::to_base64_default_or_url_value + : ((options & base64_url) ? tables::base64::to_base64_url_value + : tables::base64::to_base64_value); + const uint32_t *d0 = + (options & base64_default_or_url) + ? tables::base64::base64_default_or_url::d0 + : ((options & base64_url) ? tables::base64::base64_url::d0 + : tables::base64::base64_default::d0); + const uint32_t *d1 = + (options & base64_default_or_url) + ? tables::base64::base64_default_or_url::d1 + : ((options & base64_url) ? tables::base64::base64_url::d1 + : tables::base64::base64_default::d1); + const uint32_t *d2 = + (options & base64_default_or_url) + ? tables::base64::base64_default_or_url::d2 + : ((options & base64_url) ? tables::base64::base64_url::d2 + : tables::base64::base64_default::d2); + const uint32_t *d3 = + (options & base64_default_or_url) + ? tables::base64::base64_default_or_url::d3 + : ((options & base64_url) ? tables::base64::base64_url::d3 + : tables::base64::base64_default::d3); + const bool ignore_garbage = + (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + + const char_type *srcend = src + length; + const char_type *srcinit = src; + const char *dstinit = dst; + + uint32_t x; + size_t idx; + uint8_t buffer[4]; + while (true) { + while (srcend - src >= 4 && is_eight_byte(src[0]) && + is_eight_byte(src[1]) && is_eight_byte(src[2]) && + is_eight_byte(src[3]) && + (x = d0[uint8_t(src[0])] | d1[uint8_t(src[1])] | + d2[uint8_t(src[2])] | d3[uint8_t(src[3])]) < 0x01FFFFFF) { + if (check_capacity && dstend - dst < 3) { + return {OUTPUT_BUFFER_TOO_SMALL, size_t(src - srcinit), + size_t(dst - dstinit)}; + } + *dst++ = static_cast(x & 0xFF); + *dst++ = static_cast((x >> 8) & 0xFF); + *dst++ = static_cast((x >> 16) & 0xFF); + src += 4; + } + const char_type *srccur = src; + idx = 0; + // we need at least four characters. #ifdef __clang__ // If possible, we read four characters at a time. (It is an optimization.) if (ignore_garbage && src + 4 <= srcend) { @@ -9481,10 +10176,10 @@ simdutf_constexpr23 auto base64_tail_decode_impl(char* dst, size_t outlen, const char_type c2 = src[2]; char_type c3 = src[3]; - uint8_t code0 = toBase64[uint8_t(c0)]; - uint8_t code1 = toBase64[uint8_t(c1)]; - uint8_t code2 = toBase64[uint8_t(c2)]; - uint8_t code3 = toBase64[uint8_t(c3)]; + uint8_t code0 = to_base64[uint8_t(c0)]; + uint8_t code1 = to_base64[uint8_t(c1)]; + uint8_t code2 = to_base64[uint8_t(c2)]; + uint8_t code3 = to_base64[uint8_t(c3)]; buffer[idx] = code0; idx += (is_eight_byte(c0) && code0 <= 63); @@ -9500,13 +10195,14 @@ simdutf_constexpr23 auto base64_tail_decode_impl(char* dst, size_t outlen, const while ((idx < 4) && (src < srcend)) { char_type c = *src; - uint8_t code = toBase64[uint8_t(c)]; - buffer[idx] = code; + uint8_t code = to_base64[uint8_t(c)]; + buffer[idx] = uint8_t(code); if (is_eight_byte(c) && code <= 63) { idx++; } else if (!ignore_garbage && (code > 64 || !scalar::base64::is_eight_byte(c))) { - return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), static_cast(dst - dstinit)}; + return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), + size_t(dst - dstinit)}; } else { // We have a space or a newline or garbage. We ignore it. } @@ -9517,7 +10213,8 @@ simdutf_constexpr23 auto base64_tail_decode_impl(char* dst, size_t outlen, const // We never should have that the number of base64 characters + the // number of padding characters is more than 4. if (!ignore_garbage && (idx + padding_characters > 4)) { - return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), static_cast(dst - dstinit), true}; + return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), + size_t(dst - dstinit), true}; } // The idea here is that in loose mode, @@ -9528,66 +10225,85 @@ simdutf_constexpr23 auto base64_tail_decode_impl(char* dst, size_t outlen, const last_chunk_options == last_chunk_handling_options::loose && (idx >= 2) && padding_characters > 0 && ((idx + padding_characters) & 3) != 0) { - return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), static_cast(dst - dstinit), true}; - } + return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), + size_t(dst - dstinit), true}; + } else - // The idea here is that in strict mode, we do not want to accept - // incomplete base64 chunks. So if the chunk was otherwise valid, we - // return BASE64_INPUT_REMAINDER. - if (!ignore_garbage && last_chunk_options == last_chunk_handling_options::strict && (idx >= 2) && - ((idx + padding_characters) & 3) != 0) { + // The idea here is that in strict mode, we do not want to accept + // incomplete base64 chunks. So if the chunk was otherwise valid, we + // return BASE64_INPUT_REMAINDER. + if (!ignore_garbage && + last_chunk_options == last_chunk_handling_options::strict && + (idx >= 2) && ((idx + padding_characters) & 3) != 0) { // The partial chunk was at src - idx - return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), size_t(dst - dstinit), true}; - } else + return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), + size_t(dst - dstinit), true}; + } else // If there is a partial chunk with insufficient padding, with // stop_before_partial, we need to just ignore it. In "only full" // mode, skip the minute there are padding characters. - if ((last_chunk_options == last_chunk_handling_options::stop_before_partial && - (padding_characters + idx < 4) && (idx != 0) && (idx >= 2 || padding_characters == 0)) || - (last_chunk_options == last_chunk_handling_options::only_full_chunks && + if ((last_chunk_options == + last_chunk_handling_options::stop_before_partial && + (padding_characters + idx < 4) && (idx != 0) && + (idx >= 2 || padding_characters == 0)) || + (last_chunk_options == + last_chunk_handling_options::only_full_chunks && (idx >= 2 || padding_characters == 0))) { - // partial means that we are *not* going to consume the read - // characters. We need to rewind the src pointer. - src = srccur; - return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; + // partial means that we are *not* going to consume the read + // characters. We need to rewind the src pointer. + src = srccur; + return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; } else { - if (idx == 2) { - uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + (uint32_t(buffer[1]) << 2 * 6); - if (!ignore_garbage && (last_chunk_options == last_chunk_handling_options::strict) && - (triple & 0xffff)) { - return {BASE64_EXTRA_BITS, size_t(src - srcinit), size_t(dst - dstinit)}; - } - if (check_capacity && dstend - dst < 1) { - return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), size_t(dst - dstinit)}; - } - *dst++ = static_cast((triple >> 16) & 0xFF); - } else if (idx == 3) { - uint32_t triple = - (uint32_t(buffer[0]) << 3 * 6) + (uint32_t(buffer[1]) << 2 * 6) + (uint32_t(buffer[2]) << 1 * 6); - if (!ignore_garbage && (last_chunk_options == last_chunk_handling_options::strict) && - (triple & 0xff)) { - return {BASE64_EXTRA_BITS, size_t(src - srcinit), size_t(dst - dstinit)}; - } - if (check_capacity && dstend - dst < 2) { - return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), size_t(dst - dstinit)}; - } - *dst++ = static_cast((triple >> 16) & 0xFF); - *dst++ = static_cast((triple >> 8) & 0xFF); - } else if (!ignore_garbage && idx == 1 && - (!is_partial(last_chunk_options) || - (is_partial(last_chunk_options) && padding_characters > 0))) { - return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), size_t(dst - dstinit)}; - } else if (!ignore_garbage && idx == 0 && padding_characters > 0) { - return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), size_t(dst - dstinit), true}; + if (idx == 2) { + uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + + (uint32_t(buffer[1]) << 2 * 6); + if (!ignore_garbage && + (last_chunk_options == last_chunk_handling_options::strict) && + (triple & 0xffff)) { + return {BASE64_EXTRA_BITS, size_t(src - srcinit), + size_t(dst - dstinit)}; + } + if (check_capacity && dstend - dst < 1) { + return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), + size_t(dst - dstinit)}; + } + *dst++ = static_cast((triple >> 16) & 0xFF); + } else if (idx == 3) { + uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + + (uint32_t(buffer[1]) << 2 * 6) + + (uint32_t(buffer[2]) << 1 * 6); + if (!ignore_garbage && + (last_chunk_options == last_chunk_handling_options::strict) && + (triple & 0xff)) { + return {BASE64_EXTRA_BITS, size_t(src - srcinit), + size_t(dst - dstinit)}; + } + if (check_capacity && dstend - dst < 2) { + return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), + size_t(dst - dstinit)}; } - return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; + *dst++ = static_cast((triple >> 16) & 0xFF); + *dst++ = static_cast((triple >> 8) & 0xFF); + } else if (!ignore_garbage && idx == 1 && + (!is_partial(last_chunk_options) || + (is_partial(last_chunk_options) && + padding_characters > 0))) { + return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), + size_t(dst - dstinit)}; + } else if (!ignore_garbage && idx == 0 && padding_characters > 0) { + return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), + size_t(dst - dstinit), true}; + } + return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; } } if (check_capacity && dstend - dst < 3) { - return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), static_cast(dst - dstinit)}; + return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), + size_t(dst - dstinit)}; } - uint32_t triple = (static_cast(buffer[0]) << 3 * 6) + (static_cast(buffer[1]) << 2 * 6) + - (static_cast(buffer[2]) << 1 * 6) + (static_cast(buffer[3]) << 0 * 6); + uint32_t triple = + (uint32_t(buffer[0]) << 3 * 6) + (uint32_t(buffer[1]) << 2 * 6) + + (uint32_t(buffer[2]) << 1 * 6) + (uint32_t(buffer[3]) << 0 * 6); *dst++ = static_cast((triple >> 16) & 0xFF); *dst++ = static_cast((triple >> 8) & 0xFF); *dst++ = static_cast(triple & 0xFF); @@ -9595,12 +10311,13 @@ simdutf_constexpr23 auto base64_tail_decode_impl(char* dst, size_t outlen, const } template -simdutf_constexpr23 auto base64_tail_decode(char* dst, const char_type* src, size_t length, - size_t paddingCharacters, // number of padding characters - // '=', typically 0, 1, 2. - base64_options options, last_chunk_handling_options lastChunkOptions) - -> full_result { - return base64_tail_decode_impl(dst, 0, src, length, paddingCharacters, options, lastChunkOptions); +simdutf_constexpr23 full_result base64_tail_decode( + char *dst, const char_type *src, size_t length, + size_t padding_characters, // number of padding characters + // '=', typically 0, 1, 2. + base64_options options, last_chunk_handling_options last_chunk_options) { + return base64_tail_decode_impl(dst, 0, src, length, padding_characters, + options, last_chunk_options); } // like base64_tail_decode, but it will not write past the end of the output @@ -9608,308 +10325,318 @@ simdutf_constexpr23 auto base64_tail_decode(char* dst, const char_type* src, siz // written. This functions assumes that the padding (=) has been removed. // template -simdutf_constexpr23 auto base64_tail_decode_safe(char* dst, size_t outlen, const char_type* src, size_t length, - size_t paddingCharacters, // number of padding characters - // '=', typically 0, 1, 2. - base64_options options, last_chunk_handling_options lastChunkOptions) - -> full_result { - return base64_tail_decode_impl(dst, outlen, src, length, paddingCharacters, options, lastChunkOptions); -} - -simdutf_constexpr23 auto patch_tail_result(full_result r, size_t previousInput, size_t previousOutput, - size_t equallocation, size_t fullInputLength, - last_chunk_handling_options lastChunkOptions) -> full_result { - r.input_count += previousInput; - r.outputCount += previousOutput; - if (r.paddingError) { - r.input_count = equallocation; - } +simdutf_constexpr23 full_result base64_tail_decode_safe( + char *dst, size_t outlen, const char_type *src, size_t length, + size_t padding_characters, // number of padding characters + // '=', typically 0, 1, 2. + base64_options options, last_chunk_handling_options last_chunk_options) { + return base64_tail_decode_impl(dst, outlen, src, length, + padding_characters, options, + last_chunk_options); +} - if (r.error == error_code::SUCCESS) { - if (!is_partial(lastChunkOptions)) { - // A success when we are not in stop_before_partial mode. - // means that we have consumed the whole input buffer. - r.input_count = fullInputLength; - } else if (r.outputCount % 3 != 0) { - r.input_count = fullInputLength; - } +inline simdutf_constexpr23 full_result +patch_tail_result(full_result r, size_t previous_input, size_t previous_output, + size_t equallocation, size_t full_input_length, + last_chunk_handling_options last_chunk_options) { + r.input_count += previous_input; + r.output_count += previous_output; + if (r.padding_error) { + r.input_count = equallocation; + } + + if (r.error == error_code::SUCCESS) { + if (!is_partial(last_chunk_options)) { + // A success when we are not in stop_before_partial mode. + // means that we have consumed the whole input buffer. + r.input_count = full_input_length; + } else if (r.output_count % 3 != 0) { + r.input_count = full_input_length; } - return r; + } + return r; } // Returns the number of bytes written. The destination buffer must be large // enough. It will add padding (=) if needed. template -simdutf_constexpr23 auto tail_encode_base64_impl(char* dst, const char* src, size_t srclen, base64_options options, - size_t line_length = simdutf::defaultLineLength, size_t lineOffset = 0) - -> size_t { +simdutf_constexpr23 size_t tail_encode_base64_impl( + char *dst, const char *src, size_t srclen, base64_options options, + size_t line_length = simdutf::default_line_length, size_t line_offset = 0) { + if constexpr (use_lines) { + // sanitize line_length and starting_line_offset. + // line_length must be greater than 3. + if (line_length < 4) { + line_length = 4; + } + simdutf_log_assert(line_offset <= line_length, + "line_offset should be less than line_length"); + } + // By default, we use padding if we are not using the URL variant. + // This is check with ((options & base64_url) == 0) which returns true if we + // are not using the URL variant. However, we also allow 'inversion' of the + // convention with the base64_reverse_padding option. If the + // base64_reverse_padding option is set, we use padding if we are using the + // URL variant, and we omit it if we are not using the URL variant. This is + // checked with + // ((options & base64_reverse_padding) == base64_reverse_padding). + bool use_padding = + ((options & base64_url) == 0) ^ + ((options & base64_reverse_padding) == base64_reverse_padding); + // This looks like 3 branches, but we expect the compiler to resolve this to + // a single branch: + const char *e0 = (options & base64_url) ? tables::base64::base64_url::e0 + : tables::base64::base64_default::e0; + const char *e1 = (options & base64_url) ? tables::base64::base64_url::e1 + : tables::base64::base64_default::e1; + const char *e2 = (options & base64_url) ? tables::base64::base64_url::e2 + : tables::base64::base64_default::e2; + char *out = dst; + size_t i = 0; + uint8_t t1, t2, t3; + for (; i + 2 < srclen; i += 3) { + t1 = uint8_t(src[i]); + t2 = uint8_t(src[i + 1]); + t3 = uint8_t(src[i + 2]); if constexpr (use_lines) { - // sanitize line_length and starting_line_offset. - // line_length must be greater than 3. - line_length = std::max(line_length, 4); - simdutf_log_assert(line_offset <= line_length, "line_offset should be less than line_length"); + if (line_offset + 3 >= line_length) { + if (line_offset == line_length) { + *out++ = '\n'; + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; + line_offset = 4; + } else if (line_offset + 1 == line_length) { + *out++ = e0[t1]; + *out++ = '\n'; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; + line_offset = 3; + } else if (line_offset + 2 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = '\n'; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; + line_offset = 2; + } else if (line_offset + 3 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = '\n'; + *out++ = e2[t3]; + line_offset = 1; + } + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; + line_offset += 4; + } + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *out++ = e2[t3]; } - // By default, we use padding if we are not using the URL variant. - // This is check with ((options & base64_url) == 0) which returns true if we - // are not using the URL variant. However, we also allow 'inversion' of the - // convention with the base64_reverse_padding option. If the - // base64_reverse_padding option is set, we use padding if we are using the - // URL variant, and we omit it if we are not using the URL variant. This is - // checked with - // ((options & base64_reverse_padding) == base64_reverse_padding). - bool usePadding = ((options & base64_url) == 0) ^ ((options & base64ReversePadding) == base64ReversePadding); - // This looks like 3 branches, but we expect the compiler to resolve this to - // a single branch: - const char* e0 = (options & base64_url) ? tables::base64::base64_url::e0 : tables::base64::base64_default::e0; - const char* e1 = (options & base64_url) ? tables::base64::base64_url::e1 : tables::base64::base64_default::e1; - const char* e2 = (options & base64_url) ? tables::base64::base64_url::e2 : tables::base64::base64_default::e2; - char* out = dst; - size_t i = 0; - uint8_t t1; - uint8_t t2; - uint8_t t3; - for (; i + 2 < srclen; i += 3) { - t1 = static_cast(src[i]); - t2 = static_cast(src[i + 1]); - t3 = static_cast(src[i + 2]); - if constexpr (use_lines) { - if (lineOffset + 3 >= line_length) { - if (lineOffset == line_length) { - *out++ = '\n'; - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - lineOffset = 4; - } else if (lineOffset + 1 == line_length) { - *out++ = e0[t1]; - *out++ = '\n'; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - lineOffset = 3; - } else if (lineOffset + 2 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = '\n'; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - lineOffset = 2; - } else if (lineOffset + 3 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = '\n'; - *out++ = e2[t3]; - lineOffset = 1; - } - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; - lineOffset += 4; - } + } + switch (srclen - i) { + case 0: + break; + case 1: + t1 = uint8_t(src[i]); + if constexpr (use_lines) { + if (use_padding) { + if (line_offset + 3 >= line_length) { + if (line_offset == line_length) { + *out++ = '\n'; + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '='; + *out++ = '='; + } else if (line_offset + 1 == line_length) { + *out++ = e0[t1]; + *out++ = '\n'; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '='; + *out++ = '='; + } else if (line_offset + 2 == line_length) { + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '\n'; + *out++ = '='; + *out++ = '='; + } else if (line_offset + 3 == line_length) { + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '='; + *out++ = '\n'; + *out++ = '='; + } + } else { + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + *out++ = '='; + *out++ = '='; + } + } else { + if (line_offset + 2 >= line_length) { + if (line_offset == line_length) { + *out++ = '\n'; + *out++ = e0[uint8_t(src[i])]; + *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; + } else if (line_offset + 1 == line_length) { + *out++ = e0[uint8_t(src[i])]; + *out++ = '\n'; + *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; + } else { + *out++ = e0[uint8_t(src[i])]; + *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; + // *out++ = '\n'; ==> no newline at the end of the output + } + } else { + *out++ = e0[uint8_t(src[i])]; + *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; + } + } + } else { + *out++ = e0[t1]; + *out++ = e1[(t1 & 0x03) << 4]; + if (use_padding) { + *out++ = '='; + *out++ = '='; + } + } + break; + default: /* case 2 */ + t1 = uint8_t(src[i]); + t2 = uint8_t(src[i + 1]); + if constexpr (use_lines) { + if (use_padding) { + if (line_offset + 3 >= line_length) { + if (line_offset == line_length) { + *out++ = '\n'; + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '='; + } else if (line_offset + 1 == line_length) { + *out++ = e0[t1]; + *out++ = '\n'; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '='; + } else if (line_offset + 2 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = '\n'; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '='; + } else if (line_offset + 3 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '\n'; + *out++ = '='; + } } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + *out++ = '='; + } + } else { + if (line_offset + 3 >= line_length) { + if (line_offset == line_length) { + *out++ = '\n'; + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + } else if (line_offset + 1 == line_length) { + *out++ = e0[t1]; + *out++ = '\n'; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + } else if (line_offset + 2 == line_length) { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = '\n'; + *out++ = e2[(t2 & 0x0F) << 2]; + } else { *out++ = e0[t1]; *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; - *out++ = e2[t3]; + *out++ = e2[(t2 & 0x0F) << 2]; + // *out++ = '\n'; ==> no newline at the end of the output + } + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; } + } + } else { + *out++ = e0[t1]; + *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *out++ = e2[(t2 & 0x0F) << 2]; + if (use_padding) { + *out++ = '='; + } } - switch (srclen - i) { - case 0: - break; - case 1: - t1 = static_cast(src[i]); - if constexpr (use_lines) { - if (usePadding) { - if (lineOffset + 3 >= line_length) { - if (lineOffset == line_length) { - *out++ = '\n'; - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '='; - *out++ = '='; - } else if (lineOffset + 1 == line_length) { - *out++ = e0[t1]; - *out++ = '\n'; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '='; - *out++ = '='; - } else if (lineOffset + 2 == line_length) { - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '\n'; - *out++ = '='; - *out++ = '='; - } else if (lineOffset + 3 == line_length) { - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '='; - *out++ = '\n'; - *out++ = '='; - } - } else { - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - *out++ = '='; - *out++ = '='; - } - } else { - if (lineOffset + 2 >= line_length) { - if (lineOffset == line_length) { - *out++ = '\n'; - *out++ = e0[static_cast(src[i])]; - *out++ = e1[(static_cast(src[i]) & 0x03) << 4]; - } else if (lineOffset + 1 == line_length) { - *out++ = e0[static_cast(src[i])]; - *out++ = '\n'; - *out++ = e1[(static_cast(src[i]) & 0x03) << 4]; - } else { - *out++ = e0[static_cast(src[i])]; - *out++ = e1[(static_cast(src[i]) & 0x03) << 4]; - // *out++ = '\n'; ==> no newline at the end of the output - } - } else { - *out++ = e0[static_cast(src[i])]; - *out++ = e1[(static_cast(src[i]) & 0x03) << 4]; - } - } - } else { - *out++ = e0[t1]; - *out++ = e1[(t1 & 0x03) << 4]; - if (usePadding) { - *out++ = '='; - *out++ = '='; - } - } - break; - default: /* case 2 */ - t1 = static_cast(src[i]); - t2 = static_cast(src[i + 1]); - if constexpr (use_lines) { - if (usePadding) { - if (lineOffset + 3 >= line_length) { - if (lineOffset == line_length) { - *out++ = '\n'; - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '='; - } else if (lineOffset + 1 == line_length) { - *out++ = e0[t1]; - *out++ = '\n'; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '='; - } else if (lineOffset + 2 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = '\n'; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '='; - } else if (lineOffset + 3 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '\n'; - *out++ = '='; - } - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - *out++ = '='; - } - } else { - if (lineOffset + 3 >= line_length) { - if (lineOffset == line_length) { - *out++ = '\n'; - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - } else if (lineOffset + 1 == line_length) { - *out++ = e0[t1]; - *out++ = '\n'; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - } else if (lineOffset + 2 == line_length) { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = '\n'; - *out++ = e2[(t2 & 0x0F) << 2]; - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - // *out++ = '\n'; ==> no newline at the end of the output - } - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - } - } - } else { - *out++ = e0[t1]; - *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; - *out++ = e2[(t2 & 0x0F) << 2]; - if (usePadding) { - *out++ = '='; - } - } - } - return static_cast(out - dst); + } + return (size_t)(out - dst); } // Returns the number of bytes written. The destination buffer must be large // enough. It will add padding (=) if needed. -simdutf_constexpr23 auto tail_encode_base64(char* dst, const char* src, size_t srclen, base64_options options) - -> size_t { - return tail_encode_base64_impl(dst, src, srclen, options); +inline simdutf_constexpr23 size_t tail_encode_base64(char *dst, const char *src, + size_t srclen, + base64_options options) { + return tail_encode_base64_impl(dst, src, srclen, options); } template -simdutf_warn_unused simdutf_constexpr23 auto maximal_binary_length_from_base64(InputPtr input, size_t length) noexcept - -> size_t { - // We process the padding characters ('=') at the end to make sure - // that we return an exact result when the input has no ignorable characters - // (e.g., spaces). - size_t padding = 0; - if (length > 0) { - if (input[length - 1] == '=') { - padding++; - if (length > 1 && input[length - 2] == '=') { - padding++; - } - } - } - // The input is not otherwise processed for ignorable characters or - // validation, so that the function runs in constant time (very fast). In - // practice, base64 inputs without ignorable characters are common and the - // common case are line separated inputs with relatively long lines (e.g., 76 - // characters) which leads this function to a slight (1%) overestimation of - // the output size. - // - // Of course, some inputs might contain an arbitrary number of spaces or - // newlines, which would make this function return a very pessimistic output - // size but systems that produce base64 outputs typically do not do that and - // if they do, they do not care much about minimizing memory usage. - // - // In specialized applications, users may know that their input is line - // separated, which can be checked very quickly by by iterating (e.g., over 76 - // character chunks, looking for the linefeed characters only). We could - // provide a specialized function for that, but it is not clear that the added - // complexity is worth it for us. - // - size_t actualLength = length - padding; - if (actualLength % 4 <= 1) { - return actualLength / 4 * 3; +simdutf_warn_unused simdutf_constexpr23 size_t +maximal_binary_length_from_base64(InputPtr input, size_t length) noexcept { + // We process the padding characters ('=') at the end to make sure + // that we return an exact result when the input has no ignorable characters + // (e.g., spaces). + size_t padding = 0; + if (length > 0) { + if (input[length - 1] == '=') { + padding++; + if (length > 1 && input[length - 2] == '=') { + padding++; + } } - // if we have a valid input, then the remainder must be 2 or 3 adding one or - // two extra bytes. - return (actualLength / 4 * 3) + (actualLength % 4) - 1; + } + // The input is not otherwise processed for ignorable characters or + // validation, so that the function runs in constant time (very fast). In + // practice, base64 inputs without ignorable characters are common and the + // common case are line separated inputs with relatively long lines (e.g., 76 + // characters) which leads this function to a slight (1%) overestimation of + // the output size. + // + // Of course, some inputs might contain an arbitrary number of spaces or + // newlines, which would make this function return a very pessimistic output + // size but systems that produce base64 outputs typically do not do that and + // if they do, they do not care much about minimizing memory usage. + // + // In specialized applications, users may know that their input is line + // separated, which can be checked very quickly by by iterating (e.g., over 76 + // character chunks, looking for the linefeed characters only). We could + // provide a specialized function for that, but it is not clear that the added + // complexity is worth it for us. + // + size_t actual_length = length - padding; + if (actual_length % 4 <= 1) { + return actual_length / 4 * 3; + } + // if we have a valid input, then the remainder must be 2 or 3 adding one or + // two extra bytes. + return actual_length / 4 * 3 + (actual_length % 4) - 1; } // This function computes the binary length by iterating through the input @@ -9917,151 +10644,176 @@ simdutf_warn_unused simdutf_constexpr23 auto maximal_binary_length_from_base64(I // We use a simple check (c > ' ') which is easy to parallelize and matches // SIMD behavior. Only the last few characters are checked for padding '='. template -simdutf_warn_unused simdutf_constexpr23 auto binary_length_from_base64(const char_type* input, size_t length) noexcept - -> size_t { - // Count non-whitespace characters (c > ' ') with loop unrolling - size_t count = 0; - for (size_t i = 0; i < length; i++) { - count += (input[i] > ' '); - } - - // Check for padding '=' at the end (at most 2 padding characters) - // Scan backwards, skipping whitespace, to find padding - size_t padding = 0; - size_t pos = length; - // Skip trailing whitespace - while (pos > 0 && padding < 2) { - char_type c = input[--pos]; - if (c == '=') { - padding++; - } else if (c > ' ') { - break; - } +simdutf_warn_unused simdutf_constexpr23 size_t +binary_length_from_base64(const char_type *input, size_t length) noexcept { + // Count non-whitespace characters (c > ' ') with loop unrolling + size_t count = 0; + for (size_t i = 0; i < length; i++) { + count += (input[i] > ' '); + } + + // Check for padding '=' at the end (at most 2 padding characters) + // Scan backwards, skipping whitespace, to find padding + size_t padding = 0; + size_t pos = length; + // Skip trailing whitespace + while (pos > 0 && padding < 2) { + char_type c = input[--pos]; + if (c == '=') { + padding++; + } else if (c > ' ') { + break; } - return ((count - padding) * 3) / 4; + } + return ((count - padding) * 3) / 4; } template -simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_details_impl( - const char_type* input, size_t length, char* output, base64_options options, - last_chunk_handling_options lastChunkOptions) noexcept -> full_result { - const bool ignoreGarbage = (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - auto ri = simdutf::scalar::base64::find_end(input, length, options); - size_t equallocation = ri.equallocation; - size_t equalsigns = ri.equalsigns; - length = ri.srclen; - size_t fullInputLength = ri.full_input_length; - if (length == 0) { - if (!ignoreGarbage && equalsigns > 0) { - return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; - } - return {SUCCESS, fullInputLength, 0}; - } - full_result r = scalar::base64::base64_tail_decode(output, input, length, equalsigns, options, lastChunkOptions); - r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, fullInputLength, lastChunkOptions); - if (!is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && equalsigns > 0 && !ignoreGarbage) { - // additional checks - if ((r.outputCount % 3 == 0) || ((r.outputCount % 3) + 1 + equalsigns != 4)) { - return {INVALID_BASE64_CHARACTER, equallocation, r.outputCount, true}; - } - } - // When is_partial(last_chunk_options) is true, we must either end with - // the end of the stream (beyond whitespace) or right after a non-ignorable - // character or at the very beginning of the stream. - // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 - if (is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && r.input_count < fullInputLength) { - // First check if we can extend the input to the end of the stream - while (r.input_count < fullInputLength && base64_ignorable(*(input + r.input_count), options)) { - r.input_count++; - } - // If we are still not at the end of the stream, then we must backtrack - // to the last non-ignorable character. - if (r.input_count < fullInputLength) { - while (r.input_count > 0 && base64_ignorable(*(input + r.input_count - 1), options)) { - r.input_count--; - } - } +simdutf_warn_unused simdutf_constexpr23 full_result +base64_to_binary_details_impl( + const char_type *input, size_t length, char *output, base64_options options, + last_chunk_handling_options last_chunk_options) noexcept { + const bool ignore_garbage = + (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + auto ri = simdutf::scalar::base64::find_end(input, length, options); + size_t equallocation = ri.equallocation; + size_t equalsigns = ri.equalsigns; + length = ri.srclen; + size_t full_input_length = ri.full_input_length; + if (length == 0) { + if (!ignore_garbage && equalsigns > 0) { + return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; + } + return {SUCCESS, full_input_length, 0}; + } + full_result r = scalar::base64::base64_tail_decode( + output, input, length, equalsigns, options, last_chunk_options); + r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, + full_input_length, last_chunk_options); + if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && + equalsigns > 0 && !ignore_garbage) { + // additional checks + if ((r.output_count % 3 == 0) || + ((r.output_count % 3) + 1 + equalsigns != 4)) { + return {INVALID_BASE64_CHARACTER, equallocation, r.output_count, true}; + } + } + // When is_partial(last_chunk_options) is true, we must either end with + // the end of the stream (beyond whitespace) or right after a non-ignorable + // character or at the very beginning of the stream. + // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 + if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && + r.input_count < full_input_length) { + // First check if we can extend the input to the end of the stream + while (r.input_count < full_input_length && + base64_ignorable(*(input + r.input_count), options)) { + r.input_count++; + } + // If we are still not at the end of the stream, then we must backtrack + // to the last non-ignorable character. + if (r.input_count < full_input_length) { + while (r.input_count > 0 && + base64_ignorable(*(input + r.input_count - 1), options)) { + r.input_count--; + } } - return r; + } + return r; } template -simdutf_constexpr23 simdutf_warn_unused auto base64_to_binary_details_safe_impl( - const char_type* input, size_t length, char* output, size_t outlen, base64_options options, - last_chunk_handling_options lastChunkOptions) noexcept -> full_result { - const bool ignoreGarbage = (options == base64_options::base64_url_accept_garbage) || - (options == base64_options::base64_default_accept_garbage) || - (options == base64_options::base64_default_or_url_accept_garbage); - auto ri = simdutf::scalar::base64::find_end(input, length, options); - size_t equallocation = ri.equallocation; - size_t equalsigns = ri.equalsigns; - length = ri.srclen; - size_t fullInputLength = ri.full_input_length; - if (length == 0) { - if (!ignoreGarbage && equalsigns > 0) { - return {INVALID_BASE64_CHARACTER, equallocation, 0}; - } - return {SUCCESS, fullInputLength, 0}; - } - full_result r = - scalar::base64::base64_tail_decode_safe(output, outlen, input, length, equalsigns, options, lastChunkOptions); - r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, fullInputLength, lastChunkOptions); - if (!is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && equalsigns > 0 && !ignoreGarbage) { - // additional checks - if ((r.outputCount % 3 == 0) || ((r.outputCount % 3) + 1 + equalsigns != 4)) { - return {INVALID_BASE64_CHARACTER, equallocation, r.outputCount}; - } +simdutf_constexpr23 simdutf_warn_unused full_result +base64_to_binary_details_safe_impl( + const char_type *input, size_t length, char *output, size_t outlen, + base64_options options, + last_chunk_handling_options last_chunk_options) noexcept { + const bool ignore_garbage = + (options == base64_options::base64_url_accept_garbage) || + (options == base64_options::base64_default_accept_garbage) || + (options == base64_options::base64_default_or_url_accept_garbage); + auto ri = simdutf::scalar::base64::find_end(input, length, options); + size_t equallocation = ri.equallocation; + size_t equalsigns = ri.equalsigns; + length = ri.srclen; + size_t full_input_length = ri.full_input_length; + if (length == 0) { + if (!ignore_garbage && equalsigns > 0) { + return {INVALID_BASE64_CHARACTER, equallocation, 0}; + } + return {SUCCESS, full_input_length, 0}; + } + full_result r = scalar::base64::base64_tail_decode_safe( + output, outlen, input, length, equalsigns, options, last_chunk_options); + r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, + full_input_length, last_chunk_options); + if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && + equalsigns > 0 && !ignore_garbage) { + // additional checks + if ((r.output_count % 3 == 0) || + ((r.output_count % 3) + 1 + equalsigns != 4)) { + return {INVALID_BASE64_CHARACTER, equallocation, r.output_count}; + } + } + + // When is_partial(last_chunk_options) is true, we must either end with + // the end of the stream (beyond whitespace) or right after a non-ignorable + // character or at the very beginning of the stream. + // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 + if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && + r.input_count < full_input_length) { + // First check if we can extend the input to the end of the stream + while (r.input_count < full_input_length && + base64_ignorable(*(input + r.input_count), options)) { + r.input_count++; + } + // If we are still not at the end of the stream, then we must backtrack + // to the last non-ignorable character. + if (r.input_count < full_input_length) { + while (r.input_count > 0 && + base64_ignorable(*(input + r.input_count - 1), options)) { + r.input_count--; + } } + } + return r; +} - // When is_partial(last_chunk_options) is true, we must either end with - // the end of the stream (beyond whitespace) or right after a non-ignorable - // character or at the very beginning of the stream. - // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 - if (is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && r.input_count < fullInputLength) { - // First check if we can extend the input to the end of the stream - while (r.input_count < fullInputLength && base64_ignorable(*(input + r.input_count), options)) { - r.input_count++; - } - // If we are still not at the end of the stream, then we must backtrack - // to the last non-ignorable character. - if (r.input_count < fullInputLength) { - while (r.input_count > 0 && base64_ignorable(*(input + r.input_count - 1), options)) { - r.input_count--; - } - } - } - return r; -} - -simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary(size_t length, base64_options options) noexcept - -> size_t { - // By default, we use padding if we are not using the URL variant. - // This is check with ((options & base64_url) == 0) which returns true if we - // are not using the URL variant. However, we also allow 'inversion' of the - // convention with the base64_reverse_padding option. If the - // base64_reverse_padding option is set, we use padding if we are using the - // URL variant, and we omit it if we are not using the URL variant. This is - // checked with - // ((options & base64_reverse_padding) == base64_reverse_padding). - bool usePadding = ((options & base64_url) == 0) ^ ((options & base64ReversePadding) == base64ReversePadding); - if (!usePadding) { - return (length / 3 * 4) + (((length % 3) != 0u) ? (length % 3) + 1 : 0); - } - return (length + 2) / 3 * 4; // We use padding to make the length a multiple of 4. +simdutf_warn_unused simdutf_constexpr23 size_t +base64_length_from_binary(size_t length, base64_options options) noexcept { + // By default, we use padding if we are not using the URL variant. + // This is check with ((options & base64_url) == 0) which returns true if we + // are not using the URL variant. However, we also allow 'inversion' of the + // convention with the base64_reverse_padding option. If the + // base64_reverse_padding option is set, we use padding if we are using the + // URL variant, and we omit it if we are not using the URL variant. This is + // checked with + // ((options & base64_reverse_padding) == base64_reverse_padding). + bool use_padding = + ((options & base64_url) == 0) ^ + ((options & base64_reverse_padding) == base64_reverse_padding); + if (!use_padding) { + return length / 3 * 4 + ((length % 3) ? (length % 3) + 1 : 0); + } + return (length + 2) / 3 * + 4; // We use padding to make the length a multiple of 4. } -simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary_with_lines(size_t length, base64_options options, - size_t line_length) noexcept - -> size_t { - if (length == 0) { - return 0; - } - size_t base64Length = scalar::base64::base64_length_from_binary(length, options); - line_length = std::max(line_length, 4); - size_t lines = (base64Length + line_length - 1) / line_length; // number of lines - return base64Length + lines - 1; +simdutf_warn_unused simdutf_constexpr23 size_t +base64_length_from_binary_with_lines(size_t length, base64_options options, + size_t line_length) noexcept { + if (length == 0) { + return 0; + } + size_t base64_length = + scalar::base64::base64_length_from_binary(length, options); + if (line_length < 4) { + line_length = 4; + } + size_t lines = + (base64_length + line_length - 1) / line_length; // number of lines + return base64_length + lines - 1; } // Return the length of the prefix that contains count base64 characters. @@ -10070,73 +10822,76 @@ simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary_with_line // The function returns (size_t)-1 if there is not enough base64 characters in // the input. template -simdutf_warn_unused auto prefix_length(size_t count, simdutf::base64_options options, const char_type* input, - size_t length) noexcept -> size_t { - size_t i = 0; - while (i < length && is_ignorable(input[i], options)) { - i++; +simdutf_warn_unused size_t prefix_length(size_t count, + simdutf::base64_options options, + const char_type *input, + size_t length) noexcept { + size_t i = 0; + while (i < length && is_ignorable(input[i], options)) { + i++; + } + if (count == 0) { + return i; // duh! + } + for (; i < length; i++) { + if (is_ignorable(input[i], options)) { + continue; } + // We have a base64 character or a padding character. + count--; if (count == 0) { - return i; // duh! - } - for (; i < length; i++) { - if (is_ignorable(input[i], options)) { - continue; - } - // We have a base64 character or a padding character. - count--; - if (count == 0) { - return i + 1; - } + return i + 1; } - simdutf_log_assert(false, "You never get here"); + } + simdutf_log_assert(false, "You never get here"); - return -1; // should never happen + return -1; // should never happen } } // namespace base64 } // unnamed namespace -} // namespace simdutf::scalar +} // namespace scalar +} // namespace simdutf #endif /* end file include/simdutf/scalar/base64.h */ namespace simdutf { -inline auto to_string(base64_options options) -> std::string_view { - switch (options) { - case base64_default: - return "base64_default"; - case base64_url: - return "base64_url"; - case base64ReversePadding: - return "base64_reverse_padding"; - case base64_url_with_padding: - return "base64_url_with_padding"; - case base64_default_accept_garbage: - return "base64_default_accept_garbage"; - case base64_url_accept_garbage: - return "base64_url_accept_garbage"; - case base64_default_or_url: - return "base64_default_or_url"; - case base64_default_or_url_accept_garbage: - return "base64_default_or_url_accept_garbage"; - } - return ""; -} - -inline auto to_string(last_chunk_handling_options options) -> std::string_view { - switch (options) { - case loose: - return "loose"; - case strict: - return "strict"; - case stop_before_partial: - return "stop_before_partial"; - case only_full_chunks: - return "only_full_chunks"; - } - return ""; +inline std::string_view to_string(base64_options options) { + switch (options) { + case base64_default: + return "base64_default"; + case base64_url: + return "base64_url"; + case base64_reverse_padding: + return "base64_reverse_padding"; + case base64_url_with_padding: + return "base64_url_with_padding"; + case base64_default_accept_garbage: + return "base64_default_accept_garbage"; + case base64_url_accept_garbage: + return "base64_url_accept_garbage"; + case base64_default_or_url: + return "base64_default_or_url"; + case base64_default_or_url_accept_garbage: + return "base64_default_or_url_accept_garbage"; + } + return ""; +} + +inline std::string_view to_string(last_chunk_handling_options options) { + switch (options) { + case loose: + return "loose"; + case strict: + return "strict"; + case stop_before_partial: + return "stop_before_partial"; + case only_full_chunks: + return "only_full_chunks"; + } + return ""; } /** @@ -10152,22 +10907,24 @@ inline auto to_string(last_chunk_handling_options options) -> std::string_view { * @param length the length of the base64 input in bytes * @return maximum number of binary bytes */ -simdutf_warn_unused auto maximal_binary_length_from_base64(const char* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto maximal_binary_length_from_base64( - const detail::input_span_of_byte_like auto& input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::maximal_binary_length_from_base64(detail::constexpr_cast_ptr(input.data()), - input.size()); - } else -#endif - { +simdutf_warn_unused size_t +maximal_binary_length_from_base64(const char *input, size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +maximal_binary_length_from_base64( + const detail::input_span_of_byte_like auto &input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::maximal_binary_length_from_base64( + detail::constexpr_cast_ptr(input.data()), input.size()); + } else + #endif + { return maximal_binary_length_from_base64( reinterpret_cast(input.data()), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Provide the maximal binary length in bytes given the base64 input. @@ -10183,20 +10940,22 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto maximal_binar * @param length the length of the base64 input in 16-bit units * @return maximal number of binary bytes */ -simdutf_warn_unused auto maximal_binary_length_from_base64(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto maximal_binary_length_from_base64(std::span input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::maximal_binary_length_from_base64(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused size_t maximal_binary_length_from_base64( + const char16_t *input, size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +maximal_binary_length_from_base64(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::maximal_binary_length_from_base64(input.data(), + input.size()); + } else + #endif + { return maximal_binary_length_from_base64(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the binary length from a base64 input. @@ -10212,21 +10971,24 @@ simdutf_really_inline simdutf_warn_unused * @param length the length of the base64 input in bytes * @return number of binary bytes */ -simdutf_warn_unused auto binary_length_from_base64(const char* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_length_from_base64( - const detail::input_span_of_byte_like auto& input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::binary_length_from_base64(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused size_t binary_length_from_base64(const char *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +binary_length_from_base64( + const detail::input_span_of_byte_like auto &input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::binary_length_from_base64(input.data(), + input.size()); + } else + #endif + { return binary_length_from_base64( reinterpret_cast(input.data()), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Compute the binary length from a base64 input. @@ -10243,20 +11005,22 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_length * @param length the length of the base64 input in 16-bit units * @return number of binary bytes */ -simdutf_warn_unused auto binary_length_from_base64(const char16_t* input, size_t length) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused - simdutf_constexpr23 auto binary_length_from_base64(std::span input) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::binary_length_from_base64(input.data(), input.size()); - } else -#endif - { +simdutf_warn_unused size_t binary_length_from_base64(const char16_t *input, + size_t length) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +binary_length_from_base64(std::span input) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::binary_length_from_base64(input.data(), + input.size()); + } else + #endif + { return binary_length_from_base64(input.data(), input.size()); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output. @@ -10312,25 +11076,32 @@ simdutf_really_inline simdutf_warn_unused * fields error and count) with an error code and either position of the error * (in the input in bytes) if any, or the number of bytes written if successful. */ -simdutf_warn_unused auto base64_to_binary(const char* input, size_t length, char* output, - base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = loose) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary( - const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::base64_to_binary_details_impl(input.data(), input.size(), binaryOutput.data(), options, - lastChunkOptions); - } else -#endif - { - return base64_to_binary(reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binaryOutput.data()), options, lastChunkOptions); +simdutf_warn_unused result base64_to_binary( + const char *input, size_t length, char *output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +base64_to_binary( + const detail::input_span_of_byte_like auto &input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::base64_to_binary_details_impl( + input.data(), input.size(), binary_output.data(), options, + last_chunk_options); + } else + #endif + { + return base64_to_binary(reinterpret_cast(input.data()), + input.size(), + reinterpret_cast(binary_output.data()), + options, last_chunk_options); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Provide the base64 length in bytes given the length of a binary input. @@ -10338,10 +11109,9 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_bin * @param length the length of the input in bytes * @return number of base64 bytes */ -simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary(size_t length, - base64_options options = base64_default) noexcept - -> size_t { - return scalar::base64::base64_length_from_binary(length, options); +inline simdutf_warn_unused simdutf_constexpr23 size_t base64_length_from_binary( + size_t length, base64_options options = base64_default) noexcept { + return scalar::base64::base64_length_from_binary(length, options); } /** @@ -10353,9 +11123,12 @@ simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary(size_t le * interpreted as 4), * @return number of base64 bytes */ -simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary_with_lines( - size_t length, base64_options options = base64_default, size_t lineLength = defaultLineLength) noexcept -> size_t { - return scalar::base64::base64_length_from_binary_with_lines(length, options, lineLength); +inline simdutf_warn_unused simdutf_constexpr23 size_t +base64_length_from_binary_with_lines( + size_t length, base64_options options = base64_default, + size_t line_length = default_line_length) noexcept { + return scalar::base64::base64_length_from_binary_with_lines(length, options, + line_length); } /** @@ -10379,23 +11152,26 @@ simdutf_warn_unused simdutf_constexpr23 auto base64_length_from_binary_with_line * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ -auto binary_to_base64(const char* input, size_t length, char* output, base64_options options = base64_default) noexcept - -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_to_base64( - const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::tail_encode_base64(binaryOutput.data(), input.data(), input.size(), options); - } else -#endif - { - return binary_to_base64(reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binaryOutput.data()), options); +size_t binary_to_base64(const char *input, size_t length, char *output, + base64_options options = base64_default) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +binary_to_base64(const detail::input_span_of_byte_like auto &input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::tail_encode_base64( + binary_output.data(), input.data(), input.size(), options); + } else + #endif + { + return binary_to_base64( + reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binary_output.data()), options); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert a binary input to a base64 output with line breaks. @@ -10421,27 +11197,32 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_to_bas * @return number of written bytes, will be equal to * base64_length_from_binary_with_lines(length, options) */ -auto binary_to_base64_with_lines(const char* input, size_t length, char* output, - size_t lineLength = simdutf::defaultLineLength, - base64_options options = base64_default) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_to_base64_with_lines( - const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, - size_t lineLength = simdutf::defaultLineLength, base64_options options = base64_default) noexcept -> size_t { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::tail_encode_base64_impl(binaryOutput.data(), input.data(), input.size(), options, - lineLength); - } else -#endif - { - return binary_to_base64_with_lines(reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binaryOutput.data()), lineLength, options); +size_t +binary_to_base64_with_lines(const char *input, size_t length, char *output, + size_t line_length = simdutf::default_line_length, + base64_options options = base64_default) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t +binary_to_base64_with_lines( + const detail::input_span_of_byte_like auto &input, + detail::output_span_of_byte_like auto &&binary_output, + size_t line_length = simdutf::default_line_length, + base64_options options = base64_default) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::tail_encode_base64_impl( + binary_output.data(), input.data(), input.size(), options, line_length); + } else + #endif + { + return binary_to_base64_with_lines( + reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binary_output.data()), line_length, options); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN -#if SIMDUTF_ATOMIC_REF + #if SIMDUTF_ATOMIC_REF /** * Convert a binary input to a base64 output, using atomic accesses. * This function comes with a potentially significant performance @@ -10483,17 +11264,20 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto binary_to_bas * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ -auto atomic_binary_to_base64(const char* input, size_t length, char* output, - base64_options options = base64_default) noexcept -> size_t; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused auto atomic_binary_to_base64( - const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default) noexcept -> size_t { - return atomic_binary_to_base64(reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binaryOutput.data()), options); +size_t +atomic_binary_to_base64(const char *input, size_t length, char *output, + base64_options options = base64_default) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused size_t +atomic_binary_to_base64(const detail::input_span_of_byte_like auto &input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default) noexcept { + return atomic_binary_to_base64( + reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binary_output.data()), options); } -#endif // SIMDUTF_SPAN -#endif // SIMDUTF_ATOMIC_REF + #endif // SIMDUTF_SPAN + #endif // SIMDUTF_ATOMIC_REF /** * Convert a base64 input to a binary output. @@ -10551,25 +11335,32 @@ simdutf_really_inline simdutf_warn_unused auto atomic_binary_to_base64( * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number * of bytes written if successful. */ -simdutf_warn_unused auto base64_to_binary( - const char16_t* input, size_t length, char* output, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) noexcept -> result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary( - std::span input, detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose) noexcept -> result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::base64_to_binary_details_impl(input.data(), input.size(), binaryOutput.data(), options, - lastChunkOptions); - } else -#endif - { - return base64_to_binary(input.data(), input.size(), reinterpret_cast(binaryOutput.data()), options, - lastChunkOptions); +simdutf_warn_unused result +base64_to_binary(const char16_t *input, size_t length, char *output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result +base64_to_binary( + std::span input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::base64_to_binary_details_impl( + input.data(), input.size(), binary_output.data(), options, + last_chunk_options); + } else + #endif + { + return base64_to_binary(input.data(), input.size(), + reinterpret_cast(binary_output.data()), + options, last_chunk_options); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output while returning more details @@ -10618,26 +11409,33 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_bin * @return a full_result struct (of type simdutf::full_result containing the * three fields error, input_count and output_count). */ -simdutf_warn_unused auto base64_to_binary_details( - const char* input, size_t length, char* output, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) noexcept -> full_result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_details( - const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose) noexcept - -> full_result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::base64_to_binary_details_impl(input.data(), input.size(), binaryOutput.data(), options, - lastChunkOptions); - } else -#endif - { - return base64_to_binary_details(reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binaryOutput.data()), options, lastChunkOptions); +simdutf_warn_unused full_result +base64_to_binary_details(const char *input, size_t length, char *output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result +base64_to_binary_details( + const detail::input_span_of_byte_like auto &input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::base64_to_binary_details_impl( + input.data(), input.size(), binary_output.data(), options, + last_chunk_options); + } else + #endif + { + return base64_to_binary_details( + reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binary_output.data()), options, + last_chunk_options); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output while returning more details @@ -10687,26 +11485,33 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_bin * @return a full_result struct (of type simdutf::full_result containing the * three fields error, input_count and output_count). */ -simdutf_warn_unused auto base64_to_binary_details( - const char16_t* input, size_t length, char* output, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) noexcept -> full_result; -#if SIMDUTF_SPAN -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_details( - std::span input, detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose) noexcept - -> full_result { -#if SIMDUTF_CPLUSPLUS23 - if consteval { - return scalar::base64::base64_to_binary_details_impl(input.data(), input.size(), binaryOutput.data(), options, - lastChunkOptions); - } else -#endif - { - return base64_to_binary_details(input.data(), input.size(), reinterpret_cast(binaryOutput.data()), - options, lastChunkOptions); +simdutf_warn_unused full_result +base64_to_binary_details(const char16_t *input, size_t length, char *output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose) noexcept; + #if SIMDUTF_SPAN +simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result +base64_to_binary_details( + std::span input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose) noexcept { + #if SIMDUTF_CPLUSPLUS23 + if consteval { + return scalar::base64::base64_to_binary_details_impl( + input.data(), input.size(), binary_output.data(), options, + last_chunk_options); + } else + #endif + { + return base64_to_binary_details( + input.data(), input.size(), + reinterpret_cast(binary_output.data()), options, + last_chunk_options); } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN /** * Check if a character is an ignorable base64 character. @@ -10718,13 +11523,14 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_bin * @return true if the character is an ignorable base64 character, false * otherwise. */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_ignorable( - char input, base64_options options = base64_default) noexcept -> bool { - return scalar::base64::is_ignorable(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool +base64_ignorable(char input, base64_options options = base64_default) noexcept { + return scalar::base64::is_ignorable(input, options); } -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_ignorable( - char16_t input, base64_options options = base64_default) noexcept -> bool { - return scalar::base64::is_ignorable(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool +base64_ignorable(char16_t input, + base64_options options = base64_default) noexcept { + return scalar::base64::is_ignorable(input, options); } /** @@ -10738,13 +11544,13 @@ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_ignora * @param options the base64 options to use, is base64_default by default. * @return true if the character is a base64 character, false otherwise. */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid( - char input, base64_options options = base64_default) noexcept -> bool { - return scalar::base64::is_base64(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool +base64_valid(char input, base64_options options = base64_default) noexcept { + return scalar::base64::is_base64(input, options); } -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid( - char16_t input, base64_options options = base64_default) noexcept -> bool { - return scalar::base64::is_base64(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool +base64_valid(char16_t input, base64_options options = base64_default) noexcept { + return scalar::base64::is_base64(input, options); } /** @@ -10756,13 +11562,15 @@ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid( * @param options the base64 options to use, is base64_default by default. * @return true if the character is a base64 character, false otherwise. */ -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid_or_padding( - char input, base64_options options = base64_default) noexcept -> bool { - return scalar::base64::is_base64_or_padding(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool +base64_valid_or_padding(char input, + base64_options options = base64_default) noexcept { + return scalar::base64::is_base64_or_padding(input, options); } -simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid_or_padding( - char16_t input, base64_options options = base64_default) noexcept -> bool { - return scalar::base64::is_base64_or_padding(input, options); +simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool +base64_valid_or_padding(char16_t input, + base64_options options = base64_default) noexcept { + return scalar::base64::is_base64_or_padding(input, options); } /** @@ -10832,19 +11640,23 @@ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 auto base64_valid_ * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number * of units processed if successful. */ -simdutf_warn_unused auto base64_to_binary_safe( - const char* input, size_t length, char* output, size_t& outlen, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose, - bool decodeUpToBadChar = false) noexcept -> result; +simdutf_warn_unused result +base64_to_binary_safe(const char *input, size_t length, char *output, + size_t &outlen, base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose, + bool decode_up_to_bad_char = false) noexcept; // the span overload has moved to the bottom of the file -simdutf_warn_unused auto base64_to_binary_safe( - const char16_t* input, size_t length, char* output, size_t& outlen, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose, - bool decodeUpToBadChar = false) noexcept -> result; -// span overload moved to bottom of file +simdutf_warn_unused result +base64_to_binary_safe(const char16_t *input, size_t length, char *output, + size_t &outlen, base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose, + bool decode_up_to_bad_char = false) noexcept; + // span overload moved to bottom of file -#if SIMDUTF_ATOMIC_REF + #if SIMDUTF_ATOMIC_REF /** * Convert a base64 input to a binary output with a size limit and using atomic * operations. @@ -10884,48 +11696,57 @@ simdutf_warn_unused auto base64_to_binary_safe( * @return a result struct with an error code and count indicating error * position or success */ -simdutf_warn_unused auto atomic_base64_to_binary_safe( - const char* input, size_t length, char* output, size_t& outlen, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose, - bool decodeUpToBadChar = false) noexcept -> result; -simdutf_warn_unused auto atomic_base64_to_binary_safe(const char16_t* input, size_t length, char* output, - size_t& outlen, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = loose, - bool decodeUpToBadChar = false) noexcept -> result; -#if SIMDUTF_SPAN +simdutf_warn_unused result atomic_base64_to_binary_safe( + const char *input, size_t length, char *output, size_t &outlen, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose, + bool decode_up_to_bad_char = false) noexcept; +simdutf_warn_unused result atomic_base64_to_binary_safe( + const char16_t *input, size_t length, char *output, size_t &outlen, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose, + bool decode_up_to_bad_char = false) noexcept; + #if SIMDUTF_SPAN /** * @brief span overload * @return a tuple of result and outlen */ -simdutf_really_inline simdutf_warn_unused auto atomic_base64_to_binary_safe( - const detail::input_span_of_byte_like auto& binaryInput, detail::output_span_of_byte_like auto&& output, +simdutf_really_inline simdutf_warn_unused std::tuple +atomic_base64_to_binary_safe( + const detail::input_span_of_byte_like auto &binary_input, + detail::output_span_of_byte_like auto &&output, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose, - bool decodeUpToBadChar = false) noexcept -> std::tuple { - size_t outlen = output.size(); - auto ret = atomic_base64_to_binary_safe(reinterpret_cast(binaryInput.data()), binaryInput.size(), - reinterpret_cast(output.data()), outlen, options, lastChunkOptions, - decodeUpToBadChar); - return {ret, outlen}; + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose, + bool decode_up_to_bad_char = false) noexcept { + size_t outlen = output.size(); + auto ret = atomic_base64_to_binary_safe( + reinterpret_cast(binary_input.data()), binary_input.size(), + reinterpret_cast(output.data()), outlen, options, + last_chunk_options, decode_up_to_bad_char); + return {ret, outlen}; } /** * @brief span overload * @return a tuple of result and outlen */ -simdutf_warn_unused auto atomic_base64_to_binary_safe(std::span base64Input, - detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = loose, - bool decodeUpToBadChar = false) noexcept - -> std::tuple { - size_t outlen = binaryOutput.size(); - auto ret = atomic_base64_to_binary_safe(base64Input.data(), base64Input.size(), - reinterpret_cast(binaryOutput.data()), outlen, options, - lastChunkOptions, decodeUpToBadChar); - return {ret, outlen}; -} -#endif // SIMDUTF_SPAN -#endif // SIMDUTF_ATOMIC_REF +simdutf_warn_unused std::tuple +atomic_base64_to_binary_safe( + std::span base64_input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose, + bool decode_up_to_bad_char = false) noexcept { + size_t outlen = binary_output.size(); + auto ret = atomic_base64_to_binary_safe( + base64_input.data(), base64_input.size(), + reinterpret_cast(binary_output.data()), outlen, options, + last_chunk_options, decode_up_to_bad_char); + return {ret, outlen}; +} + #endif // SIMDUTF_SPAN + #endif // SIMDUTF_ATOMIC_REF #endif // SIMDUTF_FEATURE_BASE64 @@ -10947,9 +11768,7 @@ class implementation { * * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" */ - [[nodiscard]] virtual auto name() const noexcept -> std::string_view { - return _name; - } + virtual std::string_view name() const noexcept { return _name; } /** * The description of this implementation. @@ -10960,9 +11779,7 @@ class implementation { * * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" */ - [[nodiscard]] virtual auto description() const noexcept -> std::string_view { - return _description; - } + virtual std::string_view description() const noexcept { return _description; } /** * The instruction sets this implementation is compiled against @@ -10973,7 +11790,7 @@ class implementation { * @return true if the implementation can be safely used on the current system * (determined at runtime) */ - [[nodiscard]] auto supported_by_runtime_system() const -> bool; + bool supported_by_runtime_system() const; #if SIMDUTF_FEATURE_DETECT_ENCODING /** @@ -10982,15 +11799,17 @@ class implementation { * @param length the length of the string in bytes. * @return the encoding type detected */ - virtual auto autodetect_encoding(const char* input, size_t length) const noexcept -> encoding_type; + virtual encoding_type autodetect_encoding(const char *input, + size_t length) const noexcept; - /** + /** * This function will try to detect the possible encodings in one pass * @param input the string to identify * @param length the length of the string in bytes. * @return the encoding type detected */ - virtual auto detect_encodings(const char* input, size_t length) const noexcept -> int = 0; + virtual int detect_encodings(const char *input, + size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_DETECT_ENCODING /** @@ -11000,9 +11819,9 @@ class implementation { * * @return a mask of all required `internal::instruction_set::` values */ - [[nodiscard]] virtual auto required_instruction_sets() const -> uint32_t { - return _requiredInstructionSets; - } + virtual uint32_t required_instruction_sets() const { + return _required_instruction_sets; + } #if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING /** @@ -11014,7 +11833,8 @@ class implementation { * @param len the length of the string in bytes. * @return true if and only if the string is valid UTF-8. */ - simdutf_warn_unused virtual auto validate_utf8(const char* buf, size_t len) const noexcept -> bool = 0; + simdutf_warn_unused virtual bool validate_utf8(const char *buf, + size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 @@ -11030,8 +11850,8 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual auto validate_utf8_with_errors(const char* buf, size_t len) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + validate_utf8_with_errors(const char *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_ASCII @@ -11044,9 +11864,10 @@ class implementation { * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ - simdutf_warn_unused virtual auto validate_ascii(const char* buf, size_t len) const noexcept -> bool = 0; + simdutf_warn_unused virtual bool + validate_ascii(const char *buf, size_t len) const noexcept = 0; - /** + /** * Validate the ASCII string and stop on error. * * Overridden by each implementation. @@ -11058,8 +11879,8 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual auto validate_ascii_with_errors(const char* buf, size_t len) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + validate_ascii_with_errors(const char *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_ASCII @@ -11075,10 +11896,10 @@ class implementation { * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ - simdutf_warn_unused virtual auto validate_utf16be_as_ascii(const char16_t* buf, size_t len) const noexcept - -> bool = 0; + simdutf_warn_unused virtual bool + validate_utf16be_as_ascii(const char16_t *buf, size_t len) const noexcept = 0; - /** + /** * Validate the ASCII string as a UTF-16LE sequence. * An UTF-16 sequence is considered an ASCII sequence * if it could be converted to an ASCII string losslessly. @@ -11089,8 +11910,8 @@ class implementation { * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ - simdutf_warn_unused virtual auto validate_utf16le_as_ascii(const char16_t* buf, size_t len) const noexcept - -> bool = 0; + simdutf_warn_unused virtual bool + validate_utf16le_as_ascii(const char16_t *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING @@ -11108,7 +11929,8 @@ class implementation { * (char16_t). * @return true if and only if the string is valid UTF-16LE. */ - simdutf_warn_unused virtual auto validate_utf16le(const char16_t* buf, size_t len) const noexcept -> bool = 0; + simdutf_warn_unused virtual bool + validate_utf16le(const char16_t *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF16 @@ -11126,9 +11948,10 @@ class implementation { * (char16_t). * @return true if and only if the string is valid UTF-16BE. */ - simdutf_warn_unused virtual auto validate_utf16be(const char16_t* buf, size_t len) const noexcept -> bool = 0; + simdutf_warn_unused virtual bool + validate_utf16be(const char16_t *buf, size_t len) const noexcept = 0; - /** + /** * Validate the UTF-16LE string and stop on error. It might be faster than * validate_utf16le when an error is expected to occur early. * @@ -11144,10 +11967,11 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual auto validate_utf16le_with_errors(const char16_t* buf, size_t len) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + validate_utf16le_with_errors(const char16_t *buf, + size_t len) const noexcept = 0; - /** + /** * Validate the UTF-16BE string and stop on error. It might be faster than * validate_utf16be when an error is expected to occur early. * @@ -11163,9 +11987,10 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual auto validate_utf16be_with_errors(const char16_t* buf, size_t len) const noexcept - -> result = 0; - /** + simdutf_warn_unused virtual result + validate_utf16be_with_errors(const char16_t *buf, + size_t len) const noexcept = 0; + /** * Copies the UTF-16LE string while replacing mismatched surrogates with the * Unicode replacement character U+FFFD. We allow the input and output to be * the same buffer so that the correction is done in-place. @@ -11177,8 +12002,9 @@ class implementation { * (char16_t). * @param output the output buffer. */ - virtual void to_well_formed_utf16le(const char16_t* input, size_t len, char16_t* output) const noexcept = 0; - /** + virtual void to_well_formed_utf16le(const char16_t *input, size_t len, + char16_t *output) const noexcept = 0; + /** * Copies the UTF-16BE string while replacing mismatched surrogates with the * Unicode replacement character U+FFFD. We allow the input and output to be * the same buffer so that the correction is done in-place. @@ -11190,7 +12016,8 @@ class implementation { * (char16_t). * @param output the output buffer. */ - virtual void to_well_formed_utf16be(const char16_t* input, size_t len, char16_t* output) const noexcept = 0; + virtual void to_well_formed_utf16be(const char16_t *input, size_t len, + char16_t *output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING @@ -11206,7 +12033,8 @@ class implementation { * (char32_t). * @return true if and only if the string is valid UTF-32. */ - simdutf_warn_unused virtual auto validate_utf32(const char32_t* buf, size_t len) const noexcept -> bool = 0; + simdutf_warn_unused virtual bool + validate_utf32(const char32_t *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF32 @@ -11225,8 +12053,9 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual auto validate_utf32_with_errors(const char32_t* buf, size_t len) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + validate_utf32_with_errors(const char32_t *buf, + size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -11240,8 +12069,9 @@ class implementation { * @param utf8_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_latin1_to_utf8(const char* input, size_t length, - char* utf8Output) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_latin1_to_utf8(const char *input, size_t length, + char *utf8_output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -11255,10 +12085,11 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_latin1_to_utf16le(const char* input, size_t length, - char16_t* utf16Output) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_latin1_to_utf16le(const char *input, size_t length, + char16_t *utf16_output) const noexcept = 0; - /** + /** * Convert Latin1 string into UTF-16BE string. * * This function is suitable to work with inputs from untrusted sources. @@ -11268,8 +12099,9 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_latin1_to_utf16be(const char* input, size_t length, - char16_t* utf16Output) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_latin1_to_utf16be(const char *input, size_t length, + char16_t *utf16_output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -11283,8 +12115,9 @@ class implementation { * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_latin1_to_utf32(const char* input, size_t length, - char32_t* utf32Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_latin1_to_utf32(const char *input, size_t length, + char32_t *utf32_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 @@ -11300,10 +12133,11 @@ class implementation { * @return the number of written char; 0 if the input was not valid UTF-8 * string or if it cannot be represented as Latin1 */ - simdutf_warn_unused virtual auto convert_utf8_to_latin1(const char* input, size_t length, - char* latin1Output) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf8_to_latin1(const char *input, size_t length, + char *latin1_output) const noexcept = 0; - /** + /** * Convert possibly broken UTF-8 string into latin1 string with errors. * If the string cannot be represented as Latin1, an error * code is returned. @@ -11319,11 +12153,11 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual auto convert_utf8_to_latin1_with_errors(const char* input, size_t length, - char* latin1Output) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + convert_utf8_to_latin1_with_errors(const char *input, size_t length, + char *latin1_output) const noexcept = 0; - /** + /** * Convert valid UTF-8 string into latin1 string. * * This function assumes that the input string is valid UTF-8 and that it can @@ -11342,8 +12176,9 @@ class implementation { * @return the number of written char; 0 if the input was not valid UTF-8 * string */ - simdutf_warn_unused virtual auto convert_valid_utf8_to_latin1(const char* input, size_t length, - char* latin1Output) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf8_to_latin1(const char *input, size_t length, + char *latin1_output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -11359,10 +12194,11 @@ class implementation { * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ - simdutf_warn_unused virtual auto convert_utf8_to_utf16le(const char* input, size_t length, - char16_t* utf16Output) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf8_to_utf16le(const char *input, size_t length, + char16_t *utf16_output) const noexcept = 0; - /** + /** * Convert possibly broken UTF-8 string into UTF-16BE string. * * During the conversion also validation of the input string is done. @@ -11374,10 +12210,11 @@ class implementation { * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ - simdutf_warn_unused virtual auto convert_utf8_to_utf16be(const char* input, size_t length, - char16_t* utf16Output) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf8_to_utf16be(const char *input, size_t length, + char16_t *utf16_output) const noexcept = 0; - /** + /** * Convert possibly broken UTF-8 string into UTF-16LE string and stop on * error. * @@ -11392,11 +12229,11 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual auto convert_utf8_to_utf16le_with_errors(const char* input, size_t length, - char16_t* utf16Output) const noexcept - -> result = 0; + simdutf_warn_unused virtual result convert_utf8_to_utf16le_with_errors( + const char *input, size_t length, + char16_t *utf16_output) const noexcept = 0; - /** + /** * Convert possibly broken UTF-8 string into UTF-16BE string and stop on * error. * @@ -11411,10 +12248,10 @@ class implementation { * (in the input in code units) if any, or the number of code units validated * if successful. */ - simdutf_warn_unused virtual auto convert_utf8_to_utf16be_with_errors(const char* input, size_t length, - char16_t* utf16Output) const noexcept - -> result = 0; - /** + simdutf_warn_unused virtual result convert_utf8_to_utf16be_with_errors( + const char *input, size_t length, + char16_t *utf16_output) const noexcept = 0; + /** * Compute the number of bytes that this UTF-16LE string would require in * UTF-8 format even when the UTF-16LE content contains mismatched * surrogates that have to be replaced by the replacement character (0xFFFD). @@ -11433,11 +12270,10 @@ class implementation { * contains no surrogate, is in the Basic Multilingual Plane, and is * necessarily valid. */ - virtual simdutf_warn_unused auto utf8_length_from_utf16le_with_replacement(const char16_t* input, - size_t length) const noexcept - -> result = 0; + virtual simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( + const char16_t *input, size_t length) const noexcept = 0; - /** + /** * Compute the number of bytes that this UTF-16BE string would require in * UTF-8 format even when the UTF-16BE content contains mismatched * surrogates that have to be replaced by the replacement character (0xFFFD). @@ -11456,9 +12292,8 @@ class implementation { * contains no surrogate, is in the Basic Multilingual Plane, and is * necessarily valid. */ - virtual simdutf_warn_unused auto utf8_length_from_utf16be_with_replacement(const char16_t* input, - size_t length) const noexcept - -> result = 0; + virtual simdutf_warn_unused result utf8_length_from_utf16be_with_replacement( + const char16_t *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -11475,10 +12310,11 @@ class implementation { * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ - simdutf_warn_unused virtual auto convert_utf8_to_utf32(const char* input, size_t length, - char32_t* utf32Output) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf8_to_utf32(const char *input, size_t length, + char32_t *utf32_output) const noexcept = 0; - /** + /** * Convert possibly broken UTF-8 string into UTF-32 string and stop on error. * * During the conversion also validation of the input string is done. @@ -11492,9 +12328,9 @@ class implementation { * (in the input in code units) if any, or the number of char32_t written if * successful. */ - simdutf_warn_unused virtual auto convert_utf8_to_utf32_with_errors(const char* input, size_t length, - char32_t* utf32Output) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + convert_utf8_to_utf32_with_errors(const char *input, size_t length, + char32_t *utf32_output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -11508,10 +12344,11 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ - simdutf_warn_unused virtual auto convert_valid_utf8_to_utf16le(const char* input, size_t length, - char16_t* utf16Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf8_to_utf16le(const char *input, size_t length, + char16_t *utf16_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-8 string into UTF-16BE string. * * This function assumes that the input string is valid UTF-8. @@ -11521,8 +12358,9 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ - simdutf_warn_unused virtual auto convert_valid_utf8_to_utf16be(const char* input, size_t length, - char16_t* utf16Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf8_to_utf16be(const char *input, size_t length, + char16_t *utf16_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -11536,8 +12374,9 @@ class implementation { * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t */ - simdutf_warn_unused virtual auto convert_valid_utf8_to_utf32(const char* input, size_t length, - char32_t* utf32Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf8_to_utf32(const char *input, size_t length, + char32_t *utf32_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -11553,8 +12392,8 @@ class implementation { * @return the number of char16_t code units required to encode the UTF-8 * string as UTF-16LE */ - simdutf_warn_unused virtual auto utf16_length_from_utf8(const char* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf16_length_from_utf8(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -11572,8 +12411,8 @@ class implementation { * @return the number of char32_t code units required to encode the UTF-8 * string as UTF-32 */ - simdutf_warn_unused virtual auto utf32_length_from_utf8(const char* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf32_length_from_utf8(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -11593,10 +12432,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16LE * string or if it cannot be represented as Latin1 */ - simdutf_warn_unused virtual auto convert_utf16le_to_latin1(const char16_t* input, size_t length, - char* latin1Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf16le_to_latin1(const char16_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16BE string into Latin1 string. * * During the conversion also validation of the input string is done. @@ -11612,10 +12452,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16BE * string or if it cannot be represented as Latin1 */ - simdutf_warn_unused virtual auto convert_utf16be_to_latin1(const char16_t* input, size_t length, - char* latin1Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf16be_to_latin1(const char16_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16LE string into Latin1 string. * If the string cannot be represented as Latin1, an error * is returned. @@ -11634,11 +12475,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual auto convert_utf16le_to_latin1_with_errors(const char16_t* input, size_t length, - char* latin1Buffer) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + convert_utf16le_to_latin1_with_errors(const char16_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16BE string into Latin1 string. * If the string cannot be represented as Latin1, an error * is returned. @@ -11657,11 +12498,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual auto convert_utf16be_to_latin1_with_errors(const char16_t* input, size_t length, - char* latin1Buffer) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + convert_utf16be_to_latin1_with_errors(const char16_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-16LE string into Latin1 string. * * This function assumes that the input string is valid UTF-L16LE and that it @@ -11681,10 +12522,11 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf16le_to_latin1(const char16_t* input, size_t length, - char* latin1Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf16le_to_latin1(const char16_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-16BE string into Latin1 string. * * This function assumes that the input string is valid UTF16-BE and that it @@ -11704,8 +12546,9 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf16be_to_latin1(const char16_t* input, size_t length, - char* latin1Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf16be_to_latin1(const char16_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -11724,10 +12567,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ - simdutf_warn_unused virtual auto convert_utf16le_to_utf8(const char16_t* input, size_t length, - char* utf8Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf16le_to_utf8(const char16_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-8 string. * * During the conversion also validation of the input string is done. @@ -11742,10 +12586,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16BE * string */ - simdutf_warn_unused virtual auto convert_utf16be_to_utf8(const char16_t* input, size_t length, - char* utf8Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf16be_to_utf8(const char16_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16LE string into UTF-8 string and stop on * error. * @@ -11763,10 +12608,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual auto convert_utf16le_to_utf8_with_errors(const char16_t* input, size_t length, - char* utf8Buffer) const noexcept -> result = 0; + simdutf_warn_unused virtual result + convert_utf16le_to_utf8_with_errors(const char16_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-8 string and stop on * error. * @@ -11784,10 +12630,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual auto convert_utf16be_to_utf8_with_errors(const char16_t* input, size_t length, - char* utf8Buffer) const noexcept -> result = 0; + simdutf_warn_unused virtual result + convert_utf16be_to_utf8_with_errors(const char16_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16LE string into UTF-8 string, replacing * unpaired surrogates with the Unicode replacement character U+FFFD. * @@ -11802,11 +12649,11 @@ class implementation { * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ - simdutf_warn_unused virtual auto convert_utf16le_to_utf8_with_replacement(const char16_t* input, size_t length, - char* utf8Buffer) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t convert_utf16le_to_utf8_with_replacement( + const char16_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-8 string, replacing * unpaired surrogates with the Unicode replacement character U+FFFD. * @@ -11821,11 +12668,11 @@ class implementation { * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ - simdutf_warn_unused virtual auto convert_utf16be_to_utf8_with_replacement(const char16_t* input, size_t length, - char* utf8Buffer) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t convert_utf16be_to_utf8_with_replacement( + const char16_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-16LE string into UTF-8 string. * * This function assumes that the input string is valid UTF-16LE. @@ -11839,10 +12686,11 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf16le_to_utf8(const char16_t* input, size_t length, - char* utf8Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf16le_to_utf8(const char16_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-16BE string into UTF-8 string. * * This function assumes that the input string is valid UTF-16BE. @@ -11856,8 +12704,9 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf16be_to_utf8(const char16_t* input, size_t length, - char* utf8Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf16be_to_utf8(const char16_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -11876,10 +12725,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ - simdutf_warn_unused virtual auto convert_utf16le_to_utf32(const char16_t* input, size_t length, - char32_t* utf32Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf16le_to_utf32(const char16_t *input, size_t length, + char32_t *utf32_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-32 string. * * During the conversion also validation of the input string is done. @@ -11894,10 +12744,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-16BE * string */ - simdutf_warn_unused virtual auto convert_utf16be_to_utf32(const char16_t* input, size_t length, - char32_t* utf32Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf16be_to_utf32(const char16_t *input, size_t length, + char32_t *utf32_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16LE string into UTF-32 string and stop on * error. * @@ -11915,11 +12766,11 @@ class implementation { * (in the input in code units) if any, or the number of char32_t written if * successful. */ - simdutf_warn_unused virtual auto convert_utf16le_to_utf32_with_errors(const char16_t* input, size_t length, - char32_t* utf32Buffer) const noexcept - -> result = 0; + simdutf_warn_unused virtual result convert_utf16le_to_utf32_with_errors( + const char16_t *input, size_t length, + char32_t *utf32_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-16BE string into UTF-32 string and stop on * error. * @@ -11937,11 +12788,11 @@ class implementation { * (in the input in code units) if any, or the number of char32_t written if * successful. */ - simdutf_warn_unused virtual auto convert_utf16be_to_utf32_with_errors(const char16_t* input, size_t length, - char32_t* utf32Buffer) const noexcept - -> result = 0; + simdutf_warn_unused virtual result convert_utf16be_to_utf32_with_errors( + const char16_t *input, size_t length, + char32_t *utf32_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-16LE string into UTF-32 string. * * This function assumes that the input string is valid UTF-16LE. @@ -11955,10 +12806,11 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf16le_to_utf32(const char16_t* input, size_t length, - char32_t* utf32Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf16le_to_utf32(const char16_t *input, size_t length, + char32_t *utf32_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-16LE string into UTF-32BE string. * * This function assumes that the input string is valid UTF-16BE. @@ -11972,8 +12824,9 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf16be_to_utf32(const char16_t* input, size_t length, - char32_t* utf32Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf16be_to_utf32(const char16_t *input, size_t length, + char32_t *utf32_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 @@ -11991,10 +12844,11 @@ class implementation { * (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ - simdutf_warn_unused virtual auto utf8_length_from_utf16le(const char16_t* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf8_length_from_utf16le(const char16_t *input, + size_t length) const noexcept = 0; - /** + /** * Compute the number of bytes that this UTF-16BE string would require in * UTF-8 format. * @@ -12008,8 +12862,9 @@ class implementation { * (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-8 */ - simdutf_warn_unused virtual auto utf8_length_from_utf16be(const char16_t* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf8_length_from_utf16be(const char16_t *input, + size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12029,8 +12884,9 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-32 * string */ - simdutf_warn_unused virtual auto convert_utf32_to_latin1(const char32_t* input, size_t length, - char* latin1Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf32_to_latin1(const char32_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12053,11 +12909,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual auto convert_utf32_to_latin1_with_errors(const char32_t* input, size_t length, - char* latin1Buffer) const noexcept - -> result = 0; + simdutf_warn_unused virtual result + convert_utf32_to_latin1_with_errors(const char32_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-32 string into Latin1 string. * * This function assumes that the input string is valid UTF-32 and can be @@ -12077,8 +12933,9 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf32_to_latin1(const char32_t* input, size_t length, - char* latin1Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf32_to_latin1(const char32_t *input, size_t length, + char *latin1_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -12097,10 +12954,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-32 * string */ - simdutf_warn_unused virtual auto convert_utf32_to_utf8(const char32_t* input, size_t length, - char* utf8Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf32_to_utf8(const char32_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-32 string into UTF-8 string and stop on error. * * During the conversion also validation of the input string is done. @@ -12117,10 +12975,11 @@ class implementation { * (in the input in code units) if any, or the number of char written if * successful. */ - simdutf_warn_unused virtual auto convert_utf32_to_utf8_with_errors(const char32_t* input, size_t length, - char* utf8Buffer) const noexcept -> result = 0; + simdutf_warn_unused virtual result + convert_utf32_to_utf8_with_errors(const char32_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-32 string into UTF-8 string. * * This function assumes that the input string is valid UTF-32. @@ -12134,8 +12993,9 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf32_to_utf8(const char32_t* input, size_t length, - char* utf8Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf32_to_utf8(const char32_t *input, size_t length, + char *utf8_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -12149,9 +13009,10 @@ class implementation { * (char16_t) * @return the number of bytes required to encode the UTF-16 string as Latin1 */ - simdutf_warn_unused virtual auto utf16_length_from_latin1(size_t length) const noexcept -> size_t { - return length; - } + simdutf_warn_unused virtual size_t + utf16_length_from_latin1(size_t length) const noexcept { + return length; + } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 @@ -12170,10 +13031,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-32 * string */ - simdutf_warn_unused virtual auto convert_utf32_to_utf16le(const char32_t* input, size_t length, - char16_t* utf16Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf32_to_utf16le(const char32_t *input, size_t length, + char16_t *utf16_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-32 string into UTF-16BE string. * * During the conversion also validation of the input string is done. @@ -12188,10 +13050,11 @@ class implementation { * @return number of written code units; 0 if input is not a valid UTF-32 * string */ - simdutf_warn_unused virtual auto convert_utf32_to_utf16be(const char32_t* input, size_t length, - char16_t* utf16Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_utf32_to_utf16be(const char32_t *input, size_t length, + char16_t *utf16_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-32 string into UTF-16LE string and stop on * error. * @@ -12209,11 +13072,11 @@ class implementation { * (in the input in code units) if any, or the number of char16_t written if * successful. */ - simdutf_warn_unused virtual auto convert_utf32_to_utf16le_with_errors(const char32_t* input, size_t length, - char16_t* utf16Buffer) const noexcept - -> result = 0; + simdutf_warn_unused virtual result convert_utf32_to_utf16le_with_errors( + const char32_t *input, size_t length, + char16_t *utf16_buffer) const noexcept = 0; - /** + /** * Convert possibly broken UTF-32 string into UTF-16BE string and stop on * error. * @@ -12231,11 +13094,11 @@ class implementation { * (in the input in code units) if any, or the number of char16_t written if * successful. */ - simdutf_warn_unused virtual auto convert_utf32_to_utf16be_with_errors(const char32_t* input, size_t length, - char16_t* utf16Buffer) const noexcept - -> result = 0; + simdutf_warn_unused virtual result convert_utf32_to_utf16be_with_errors( + const char32_t *input, size_t length, + char16_t *utf16_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-32 string into UTF-16LE string. * * This function assumes that the input string is valid UTF-32. @@ -12249,10 +13112,11 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf32_to_utf16le(const char32_t* input, size_t length, - char16_t* utf16Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf32_to_utf16le(const char32_t *input, size_t length, + char16_t *utf16_buffer) const noexcept = 0; - /** + /** * Convert valid UTF-32 string into UTF-16BE string. * * This function assumes that the input string is valid UTF-32. @@ -12266,8 +13130,9 @@ class implementation { * result * @return number of written code units; 0 if conversion is not possible */ - simdutf_warn_unused virtual auto convert_valid_utf32_to_utf16be(const char32_t* input, size_t length, - char16_t* utf16Buffer) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + convert_valid_utf32_to_utf16be(const char32_t *input, size_t length, + char16_t *utf16_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 @@ -12298,8 +13163,8 @@ class implementation { * @param length the length of the string bytes * @return the number of bytes required to encode the Latin1 string as UTF-8 */ - simdutf_warn_unused virtual auto utf8_length_from_latin1(const char* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf8_length_from_latin1(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 @@ -12315,8 +13180,9 @@ class implementation { * (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-8 */ - simdutf_warn_unused virtual auto utf8_length_from_utf32(const char32_t* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf8_length_from_utf32(const char32_t *input, + size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12331,8 +13197,9 @@ class implementation { * (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ - simdutf_warn_unused virtual auto latin1_length_from_utf32(size_t length) const noexcept -> size_t { - return length; + simdutf_warn_unused virtual size_t + latin1_length_from_utf32(size_t length) const noexcept { + return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12348,8 +13215,8 @@ class implementation { * @param length the length of the string in byte * @return the number of bytes required to encode the UTF-8 string as Latin1 */ - simdutf_warn_unused virtual auto latin1_length_from_utf8(const char* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + latin1_length_from_utf8(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -12368,8 +13235,9 @@ class implementation { * @return the number of bytes required to encode the UTF-16LE string as * Latin1 */ - simdutf_warn_unused virtual auto latin1_length_from_utf16(size_t length) const noexcept -> size_t { - return length; + simdutf_warn_unused virtual size_t + latin1_length_from_utf16(size_t length) const noexcept { + return length; } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 @@ -12386,8 +13254,9 @@ class implementation { * (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-16 */ - simdutf_warn_unused virtual auto utf16_length_from_utf32(const char32_t* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf16_length_from_utf32(const char32_t *input, + size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12399,8 +13268,9 @@ class implementation { * (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ - simdutf_warn_unused virtual auto utf32_length_from_latin1(size_t length) const noexcept -> size_t { - return length; + simdutf_warn_unused virtual size_t + utf32_length_from_latin1(size_t length) const noexcept { + return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 @@ -12422,8 +13292,9 @@ class implementation { * @return the number of bytes required to encode the UTF-16LE string as * UTF-32 */ - simdutf_warn_unused virtual auto utf32_length_from_utf16le(const char16_t* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf32_length_from_utf16le(const char16_t *input, + size_t length) const noexcept = 0; /** * Compute the number of bytes that this UTF-16BE string would require in @@ -12442,8 +13313,9 @@ class implementation { * @return the number of bytes required to encode the UTF-16BE string as * UTF-32 */ - simdutf_warn_unused virtual auto utf32_length_from_utf16be(const char16_t* input, size_t length) const noexcept - -> size_t = 0; + simdutf_warn_unused virtual size_t + utf32_length_from_utf16be(const char16_t *input, + size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 @@ -12462,7 +13334,8 @@ class implementation { * (char16_t) * @return number of code points */ - simdutf_warn_unused virtual auto count_utf16le(const char16_t* input, size_t length) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + count_utf16le(const char16_t *input, size_t length) const noexcept = 0; /** * Count the number of code points (characters) in the string assuming that @@ -12479,7 +13352,8 @@ class implementation { * (char16_t) * @return number of code points */ - simdutf_warn_unused virtual auto count_utf16be(const char16_t* input, size_t length) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + count_utf16be(const char16_t *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 @@ -12495,7 +13369,8 @@ class implementation { * @param length the length of the string in bytes * @return number of code points */ - simdutf_warn_unused virtual auto count_utf8(const char* input, size_t length) const noexcept -> size_t = 0; + simdutf_warn_unused virtual size_t + count_utf8(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_BASE64 @@ -12512,7 +13387,8 @@ class implementation { * @param length the length of the base64 input in bytes * @return maximal number of binary bytes */ - simdutf_warn_unused auto maximal_binary_length_from_base64(const char* input, size_t length) const noexcept -> size_t; + simdutf_warn_unused size_t maximal_binary_length_from_base64( + const char *input, size_t length) const noexcept; /** * Provide the maximal binary length in bytes given the base64 input. @@ -12528,8 +13404,8 @@ class implementation { * @param length the length of the base64 input in 16-bit units * @return maximal number of binary bytes */ - simdutf_warn_unused auto maximal_binary_length_from_base64(const char16_t* input, size_t length) const noexcept - -> size_t; + simdutf_warn_unused size_t maximal_binary_length_from_base64( + const char16_t *input, size_t length) const noexcept; /** * Compute the binary length from a base64 input with ASCII spaces. @@ -12543,7 +13419,8 @@ class implementation { * @param length the length of the base64 input in bytes * @return number of binary bytes */ - simdutf_warn_unused virtual auto binary_length_from_base64(const char* input, size_t length) const noexcept -> size_t; + simdutf_warn_unused virtual size_t + binary_length_from_base64(const char *input, size_t length) const noexcept; /** * Compute the binary length from a base64 input with ASCII spaces. @@ -12558,8 +13435,9 @@ class implementation { * @param length the length of the base64 input in 16-bit units * @return number of binary bytes */ - simdutf_warn_unused virtual auto binary_length_from_base64(const char16_t* input, size_t length) const noexcept - -> size_t; + simdutf_warn_unused virtual size_t + binary_length_from_base64(const char16_t *input, + size_t length) const noexcept; /** * Convert a base64 input to a binary output. @@ -12593,9 +13471,11 @@ class implementation { * (in the input in bytes) if any, or the number of bytes written if * successful. */ - simdutf_warn_unused virtual auto base64_to_binary( - const char* input, size_t length, char* output, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) const noexcept -> result = 0; + simdutf_warn_unused virtual result + base64_to_binary(const char *input, size_t length, char *output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose) const noexcept = 0; /** * Convert a base64 input to a binary output while returning more details @@ -12628,10 +13508,11 @@ class implementation { * @return a full_result pair struct (of type simdutf::result containing the * three fields error, input_count and output_count). */ - simdutf_warn_unused virtual auto base64_to_binary_details( - const char* input, size_t length, char* output, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) const noexcept - -> full_result = 0; + simdutf_warn_unused virtual full_result base64_to_binary_details( + const char *input, size_t length, char *output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose) const noexcept = 0; /** * Convert a base64 input to a binary output. @@ -12666,9 +13547,11 @@ class implementation { * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the * number of bytes written if successful. */ - simdutf_warn_unused virtual auto base64_to_binary( - const char16_t* input, size_t length, char* output, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) const noexcept -> result = 0; + simdutf_warn_unused virtual result + base64_to_binary(const char16_t *input, size_t length, char *output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose) const noexcept = 0; /** * Convert a base64 input to a binary output while returning more details @@ -12701,10 +13584,11 @@ class implementation { * @return a full_result pair struct (of type simdutf::result containing the * three fields error, input_count and output_count). */ - simdutf_warn_unused virtual auto base64_to_binary_details( - const char16_t* input, size_t length, char* output, base64_options options = base64_default, - last_chunk_handling_options lastChunkOptions = last_chunk_handling_options::loose) const noexcept - -> full_result = 0; + simdutf_warn_unused virtual full_result base64_to_binary_details( + const char16_t *input, size_t length, char *output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = + last_chunk_handling_options::loose) const noexcept = 0; /** * Provide the base64 length in bytes given the length of a binary input. @@ -12714,8 +13598,8 @@ class implementation { * base64_url, is base64_default by default. * @return number of base64 bytes */ - simdutf_warn_unused auto base64_length_from_binary(size_t length, - base64_options options = base64_default) const noexcept -> size_t; + simdutf_warn_unused size_t base64_length_from_binary( + size_t length, base64_options options = base64_default) const noexcept; /** * Convert a binary input to a base64 output. @@ -12738,8 +13622,9 @@ class implementation { * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ - virtual auto binary_to_base64(const char* input, size_t length, char* output, - base64_options options = base64_default) const noexcept -> size_t = 0; + virtual size_t + binary_to_base64(const char *input, size_t length, char *output, + base64_options options = base64_default) const noexcept = 0; /** * Convert a binary input to a base64 output with lines of given length. @@ -12766,9 +13651,10 @@ class implementation { * @return number of written bytes, will be equal to * base64_length_from_binary_with_lines(length, options, line_length) */ - virtual auto binary_to_base64_with_lines(const char* input, size_t length, char* output, - size_t lineLength = simdutf::defaultLineLength, - base64_options options = base64_default) const noexcept -> size_t = 0; + virtual size_t binary_to_base64_with_lines( + const char *input, size_t length, char *output, + size_t line_length = simdutf::default_line_length, + base64_options options = base64_default) const noexcept = 0; /** * Find the first occurrence of a character in a string. If the character is @@ -12780,9 +13666,10 @@ class implementation { * or a pointer to the end of the string if the character is not found. * */ - virtual auto find(const char* start, const char* end, char character) const noexcept -> const char* = 0; - virtual auto find(const char16_t* start, const char16_t* end, char16_t character) const noexcept -> const - char16_t* = 0; + virtual const char *find(const char *start, const char *end, + char character) const noexcept = 0; + virtual const char16_t *find(const char16_t *start, const char16_t *end, + char16_t character) const noexcept = 0; #endif // SIMDUTF_FEATURE_BASE64 #ifdef SIMDUTF_INTERNAL_TESTS @@ -12808,12 +13695,14 @@ class implementation { protected: /** @private Construct an implementation with the given name and description. * For subclasses. */ - simdutf_really_inline implementation(const char* name, const char* description, uint32_t requiredInstructionSets) - : _name(name) - , _description(description) - , _requiredInstructionSets(requiredInstructionSets) {} + simdutf_really_inline implementation(const char *name, + const char *description, + uint32_t required_instruction_sets) + : _name(name), _description(description), + _required_instruction_sets(required_instruction_sets) {} - ~implementation() = default; +protected: + ~implementation() = default; private: /** @@ -12829,7 +13718,7 @@ class implementation { /** * Instruction sets required for this implementation. */ - const uint32_t _requiredInstructionSets; + const uint32_t _required_instruction_sets; }; /** @private */ @@ -12841,15 +13730,15 @@ namespace internal { class available_implementation_list { public: /** Get the list of available implementations compiled into simdutf */ - simdutf_really_inline available_implementation_list() = default; - /** Number of implementations */ - [[nodiscard]] auto size() const noexcept -> size_t; - /** STL const begin() iterator */ - [[nodiscard]] auto begin() const noexcept -> const implementation* const*; - /** STL const end() iterator */ - [[nodiscard]] auto end() const noexcept -> const implementation* const*; - - /** + simdutf_really_inline available_implementation_list() {} + /** Number of implementations */ + size_t size() const noexcept; + /** STL const begin() iterator */ + const implementation *const *begin() const noexcept; + /** STL const end() iterator */ + const implementation *const *end() const noexcept; + + /** * Get the implementation with the given name. * * Case sensitive. @@ -12862,14 +13751,14 @@ class available_implementation_list { * @param name the implementation to find, e.g. "westmere", "haswell", "arm64" * @return the implementation, or nullptr if the parse failed. */ - auto operator[](std::string_view name) const noexcept -> const implementation* { - for (const implementation* impl : *this) { - if (impl->name() == name) { - return impl; - } - } - return nullptr; + const implementation *operator[](std::string_view name) const noexcept { + for (const implementation *impl : *this) { + if (impl->name() == name) { + return impl; + } } + return nullptr; + } /** * Detect the most advanced implementation supported by the current host. @@ -12884,71 +13773,46 @@ class available_implementation_list { * an implementation that returns UNSUPPORTED_ARCHITECTURE if there is no * supported implementation. Will never return nullptr. */ - [[nodiscard]] auto detect_best_supported() const noexcept -> const implementation*; + const implementation *detect_best_supported() const noexcept; }; template class atomic_ptr { public: - atomic_ptr(T* ptr) - : _ptr{ptr} {} + atomic_ptr(T *_ptr) : ptr{_ptr} {} -#ifdef SIMDUTF_NO_THREADS - operator const T*() const { - return ptr; - } - const T& operator*() const { - return *ptr; - } - const T* operator->() const { - return ptr; - } +#if defined(SIMDUTF_NO_THREADS) + operator const T *() const { return ptr; } + const T &operator*() const { return *ptr; } + const T *operator->() const { return ptr; } - operator T*() { - return ptr; - } - T& operator*() { - return *ptr; - } - T* operator->() { - return ptr; - } - atomic_ptr& operator=(T* _ptr) { - ptr = _ptr; - return *this; - } + operator T *() { return ptr; } + T &operator*() { return *ptr; } + T *operator->() { return ptr; } + atomic_ptr &operator=(T *_ptr) { + ptr = _ptr; + return *this; + } #else - operator const T *() const { - return _ptr.load(); - } - auto operator*() const -> const T& { - return *_ptr; - } - auto operator->() const -> const T* { - return _ptr.load(); - } + operator const T *() const { return ptr.load(); } + const T &operator*() const { return *ptr; } + const T *operator->() const { return ptr.load(); } - operator T *() { - return _ptr.load(); - } - auto operator*() -> T& { - return *_ptr; - } - auto operator->() -> T* { - return _ptr.load(); - } - auto operator=(T* ptr) -> atomic_ptr& { - _ptr = ptr; - return *this; + operator T *() { return ptr.load(); } + T &operator*() { return *ptr; } + T *operator->() { return ptr.load(); } + atomic_ptr &operator=(T *_ptr) { + ptr = _ptr; + return *this; } #endif private: -#ifdef SIMDUTF_NO_THREADS - T* ptr; +#if defined(SIMDUTF_NO_THREADS) + T *ptr; #else - std::atomic _ptr; + std::atomic ptr; #endif }; @@ -12959,7 +13823,8 @@ class detect_best_supported_implementation_on_first_use; /** * The list of available implementations compiled into simdutf. */ -extern SIMDUTF_DLLIMPORTEXPORT auto get_available_implementations() -> const internal::available_implementation_list&; +extern SIMDUTF_DLLIMPORTEXPORT const internal::available_implementation_list & +get_available_implementations(); /** * The active implementation. @@ -12967,7 +13832,8 @@ extern SIMDUTF_DLLIMPORTEXPORT auto get_available_implementations() -> const int * Automatically initialized on first use to the most advanced implementation * supported by this hardware. */ -extern SIMDUTF_DLLIMPORTEXPORT auto get_active_implementation() -> internal::atomic_ptr&; +extern SIMDUTF_DLLIMPORTEXPORT internal::atomic_ptr & +get_active_implementation(); } // namespace simdutf @@ -12982,136 +13848,152 @@ extern SIMDUTF_DLLIMPORTEXPORT auto get_active_implementation() -> internal::ato namespace simdutf { template -simdutf_warn_unused simdutf_constexpr23 auto slow_base64_to_binary_safe_impl( - const chartype* input, size_t length, char* output, size_t& outlen, base64_options options, - last_chunk_handling_options lastChunkOptions) noexcept -> result { - const bool ignoreGarbage = (options & base64_default_accept_garbage) != 0; - auto ri = simdutf::scalar::base64::find_end(input, length, options); - size_t equallocation = ri.equallocation; - size_t equalsigns = ri.equalsigns; - length = ri.srclen; - size_t fullInputLength = ri.full_input_length; - (void)fullInputLength; - if (length == 0) { - outlen = 0; - if (!ignoreGarbage && equalsigns > 0) { - return {INVALID_BASE64_CHARACTER, equallocation}; - } - return {SUCCESS, 0}; - } - - // The parameters of base64_tail_decode_safe are: - // - dst: the output buffer - // - outlen: the size of the output buffer - // - srcr: the input buffer - // - length: the size of the input buffer - // - padded_characters: the number of padding characters - // - options: the options for the base64 decoder - // - last_chunk_options: the options for the last chunk - // The function will return the number of bytes written to the output buffer - // and the number of bytes read from the input buffer. - // The function will also return an error code if the input buffer is not - // valid base64. - full_result r = - scalar::base64::base64_tail_decode_safe(output, outlen, input, length, equalsigns, options, lastChunkOptions); - r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, fullInputLength, lastChunkOptions); - outlen = r.outputCount; - if (!is_partial(lastChunkOptions) && r.error == error_code::SUCCESS && equalsigns > 0) { - // additional checks - if ((outlen % 3 == 0) || ((outlen % 3) + 1 + equalsigns != 4)) { - r.error = error_code::INVALID_BASE64_CHARACTER; - } - } - return {r.error, r.input_count}; // we cannot return r itself because it gets - // converted to error/output_count +simdutf_warn_unused simdutf_constexpr23 result slow_base64_to_binary_safe_impl( + const chartype *input, size_t length, char *output, size_t &outlen, + base64_options options, + last_chunk_handling_options last_chunk_options) noexcept { + const bool ignore_garbage = (options & base64_default_accept_garbage) != 0; + auto ri = simdutf::scalar::base64::find_end(input, length, options); + size_t equallocation = ri.equallocation; + size_t equalsigns = ri.equalsigns; + length = ri.srclen; + size_t full_input_length = ri.full_input_length; + (void)full_input_length; + if (length == 0) { + outlen = 0; + if (!ignore_garbage && equalsigns > 0) { + return {INVALID_BASE64_CHARACTER, equallocation}; + } + return {SUCCESS, 0}; + } + + // The parameters of base64_tail_decode_safe are: + // - dst: the output buffer + // - outlen: the size of the output buffer + // - srcr: the input buffer + // - length: the size of the input buffer + // - padded_characters: the number of padding characters + // - options: the options for the base64 decoder + // - last_chunk_options: the options for the last chunk + // The function will return the number of bytes written to the output buffer + // and the number of bytes read from the input buffer. + // The function will also return an error code if the input buffer is not + // valid base64. + full_result r = scalar::base64::base64_tail_decode_safe( + output, outlen, input, length, equalsigns, options, last_chunk_options); + r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, + full_input_length, last_chunk_options); + outlen = r.output_count; + if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && + equalsigns > 0) { + // additional checks + if ((outlen % 3 == 0) || ((outlen % 3) + 1 + equalsigns != 4)) { + r.error = error_code::INVALID_BASE64_CHARACTER; + } + } + return {r.error, r.input_count}; // we cannot return r itself because it gets + // converted to error/output_count } template -simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_safe_impl( - const chartype* input, size_t length, char* output, size_t& outlen, base64_options options, - last_chunk_handling_options lastChunkHandlingOptions, bool decodeUpToBadChar) noexcept -> result { - static_assert(std::is_same_v || std::is_same_v, - "Only char and char16_t are supported."); - size_t remainingInputLength = length; - size_t remainingOutputLength = outlen; - size_t inputPosition = 0; - size_t outputPosition = 0; - - // We also do a first pass using the fast path to decode as much as possible - size_t safeInput = - (std::min)(remainingInputLength, base64_length_from_binary(remainingOutputLength / 3 * 3, options)); - bool doneWithPartial = (safeInput == remainingInputLength); - simdutf::full_result r; +simdutf_warn_unused simdutf_constexpr23 result base64_to_binary_safe_impl( + const chartype *input, size_t length, char *output, size_t &outlen, + base64_options options, + last_chunk_handling_options last_chunk_handling_options, + bool decode_up_to_bad_char) noexcept { + static_assert(std::is_same::value || + std::is_same::value, + "Only char and char16_t are supported."); + size_t remaining_input_length = length; + size_t remaining_output_length = outlen; + size_t input_position = 0; + size_t output_position = 0; + + // We also do a first pass using the fast path to decode as much as possible + size_t safe_input = (std::min)( + remaining_input_length, + base64_length_from_binary(remaining_output_length / 3 * 3, options)); + bool done_with_partial = (safe_input == remaining_input_length); + simdutf::full_result r; #if SIMDUTF_CPLUSPLUS23 if consteval { - r = scalar::base64::base64_to_binary_details_impl( - input + inputPosition, safeInput, output + outputPosition, options, - doneWithPartial ? lastChunkHandlingOptions : simdutf::last_chunk_handling_options::only_full_chunks); + r = scalar::base64::base64_to_binary_details_impl( + input + input_position, safe_input, output + output_position, options, + done_with_partial + ? last_chunk_handling_options + : simdutf::last_chunk_handling_options::only_full_chunks); } else #endif { - r = get_active_implementation()->base64_to_binary_details( - input + inputPosition, safeInput, output + outputPosition, options, - doneWithPartial ? lastChunkHandlingOptions : simdutf::last_chunk_handling_options::only_full_chunks); + r = get_active_implementation()->base64_to_binary_details( + input + input_position, safe_input, output + output_position, options, + done_with_partial + ? last_chunk_handling_options + : simdutf::last_chunk_handling_options::only_full_chunks); } simdutf_log_assert(r.input_count <= safe_input, "You should not read more than safe_input"); simdutf_log_assert(r.output_count <= remaining_output_length, "You should not write more than remaining_output_length"); // Technically redundant, but we want to be explicit about it. - inputPosition += r.input_count; - outputPosition += r.outputCount; - remainingInputLength -= r.input_count; - remainingOutputLength -= r.outputCount; + input_position += r.input_count; + output_position += r.output_count; + remaining_input_length -= r.input_count; + remaining_output_length -= r.output_count; if (r.error != simdutf::error_code::SUCCESS) { // There is an error. We return. - if (decodeUpToBadChar && r.error == error_code::INVALID_BASE64_CHARACTER) { - return slow_base64_to_binary_safe_impl(input, length, output, outlen, options, lastChunkHandlingOptions); + if (decode_up_to_bad_char && + r.error == error_code::INVALID_BASE64_CHARACTER) { + return slow_base64_to_binary_safe_impl( + input, length, output, outlen, options, last_chunk_handling_options); } - outlen = outputPosition; - return {r.error, inputPosition}; + outlen = output_position; + return {r.error, input_position}; } - if (doneWithPartial) { - // We are done. We have decoded everything. - outlen = outputPosition; - return {simdutf::error_code::SUCCESS, inputPosition}; + if (done_with_partial) { + // We are done. We have decoded everything. + outlen = output_position; + return {simdutf::error_code::SUCCESS, input_position}; } // We have decoded some data, but we still have some data to decode. // We need to decode the rest of the input buffer. - r = simdutf::scalar::base64::base64_to_binary_details_safe_impl(input + inputPosition, remainingInputLength, - output + outputPosition, remainingOutputLength, - options, lastChunkHandlingOptions); - inputPosition += r.input_count; - outputPosition += r.outputCount; - remainingInputLength -= r.input_count; - remainingOutputLength -= r.outputCount; + r = simdutf::scalar::base64::base64_to_binary_details_safe_impl( + input + input_position, remaining_input_length, output + output_position, + remaining_output_length, options, last_chunk_handling_options); + input_position += r.input_count; + output_position += r.output_count; + remaining_input_length -= r.input_count; + remaining_output_length -= r.output_count; if (r.error != simdutf::error_code::SUCCESS) { // There is an error. We return. - if (decodeUpToBadChar && r.error == error_code::INVALID_BASE64_CHARACTER) { - return slow_base64_to_binary_safe_impl(input, length, output, outlen, options, lastChunkHandlingOptions); + if (decode_up_to_bad_char && + r.error == error_code::INVALID_BASE64_CHARACTER) { + return slow_base64_to_binary_safe_impl( + input, length, output, outlen, options, last_chunk_handling_options); } - outlen = outputPosition; - return {r.error, inputPosition}; + outlen = output_position; + return {r.error, input_position}; } - if (inputPosition < length) { - // We cannot process the entire input in one go, so we need to - // process it in two steps: first the fast path, then the slow path. - // In some cases, the processing might 'eat up' trailing ignorable - // characters in the fast path, but that can be a problem. - // suppose we have just white space followed by a single base64 character. - // If we first process the white space with the fast path, it will - // eat all of it. But, by the JavaScript standard, we should consume - // no character. See - // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 - while (inputPosition > 0 && base64_ignorable(input[inputPosition - 1], options)) { - inputPosition--; - } + if (input_position < length) { + // We cannot process the entire input in one go, so we need to + // process it in two steps: first the fast path, then the slow path. + // In some cases, the processing might 'eat up' trailing ignorable + // characters in the fast path, but that can be a problem. + // suppose we have just white space followed by a single base64 character. + // If we first process the white space with the fast path, it will + // eat all of it. But, by the JavaScript standard, we should consume + // no character. See + // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 + while (input_position > 0 && + base64_ignorable(input[input_position - 1], options)) { + input_position--; + } } - outlen = outputPosition; - return {simdutf::error_code::SUCCESS, inputPosition}; + outlen = output_position; + return {simdutf::error_code::SUCCESS, input_position}; } } // namespace simdutf @@ -13124,58 +14006,71 @@ namespace simdutf { * @brief span overload * @return a tuple of result and outlen */ -simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused auto base64_to_binary_safe( - const detail::input_span_of_byte_like auto& input, detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose, - bool decodeUpToBadChar = false) noexcept -> std::tuple { - size_t outlen = binaryOutput.size(); -#if SIMDUTF_CPLUSPLUS23 - if consteval { - using CInput = std::decay_t; - static_assert(std::is_same_v, - "sorry, the constexpr implementation is for now limited to " - "input of type char"); - using COutput = std::decay_t; - static_assert(std::is_same_v, - "sorry, the constexpr implementation is for now limited to " - "output of type char"); - auto r = base64_to_binary_safe_impl(input.data(), input.size(), binaryOutput.data(), outlen, options, - lastChunkOptions, decodeUpToBadChar); - return {r, outlen}; - } else -#endif - { - auto r = base64_to_binary_safe_impl(reinterpret_cast(input.data()), input.size(), - reinterpret_cast(binaryOutput.data()), outlen, options, - lastChunkOptions, decodeUpToBadChar); - return {r, outlen}; +simdutf_really_inline + simdutf_constexpr23 simdutf_warn_unused std::tuple + base64_to_binary_safe( + const detail::input_span_of_byte_like auto &input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose, + bool decode_up_to_bad_char = false) noexcept { + size_t outlen = binary_output.size(); + #if SIMDUTF_CPLUSPLUS23 + if consteval { + using CInput = std::decay_t; + static_assert(std::is_same_v, + "sorry, the constexpr implementation is for now limited to " + "input of type char"); + using COutput = std::decay_t; + static_assert(std::is_same_v, + "sorry, the constexpr implementation is for now limited to " + "output of type char"); + auto r = base64_to_binary_safe_impl( + input.data(), input.size(), binary_output.data(), outlen, options, + last_chunk_options, decode_up_to_bad_char); + return {r, outlen}; + } else + #endif + { + auto r = base64_to_binary_safe_impl( + reinterpret_cast(input.data()), input.size(), + reinterpret_cast(binary_output.data()), outlen, options, + last_chunk_options, decode_up_to_bad_char); + return {r, outlen}; } } -#if SIMDUTF_SPAN + #if SIMDUTF_SPAN /** * @brief span overload * @return a tuple of result and outlen */ -simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_binary_safe( - std::span input, detail::output_span_of_byte_like auto&& binaryOutput, - base64_options options = base64_default, last_chunk_handling_options lastChunkOptions = loose, - bool decodeUpToBadChar = false) noexcept -> std::tuple { - size_t outlen = binaryOutput.size(); -#if SIMDUTF_CPLUSPLUS23 - if consteval { - auto r = base64_to_binary_safe_impl(input.data(), input.size(), binaryOutput.data(), outlen, options, - lastChunkOptions, decodeUpToBadChar); - return {r, outlen}; - } else -#endif - { - auto r = base64_to_binary_safe(input.data(), input.size(), reinterpret_cast(binaryOutput.data()), outlen, - options, lastChunkOptions, decodeUpToBadChar); - return {r, outlen}; +simdutf_really_inline + simdutf_warn_unused simdutf_constexpr23 std::tuple + base64_to_binary_safe( + std::span input, + detail::output_span_of_byte_like auto &&binary_output, + base64_options options = base64_default, + last_chunk_handling_options last_chunk_options = loose, + bool decode_up_to_bad_char = false) noexcept { + size_t outlen = binary_output.size(); + #if SIMDUTF_CPLUSPLUS23 + if consteval { + auto r = base64_to_binary_safe_impl( + input.data(), input.size(), binary_output.data(), outlen, options, + last_chunk_options, decode_up_to_bad_char); + return {r, outlen}; + } else + #endif + { + auto r = base64_to_binary_safe( + input.data(), input.size(), + reinterpret_cast(binary_output.data()), outlen, options, + last_chunk_options, decode_up_to_bad_char); + return {r, outlen}; } } -#endif // SIMDUTF_SPAN + #endif // SIMDUTF_SPAN #endif // SIMDUTF_SPAN } // namespace simdutf @@ -13184,7 +14079,8 @@ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 auto base64_to_bin #if SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64 -namespace simdutf::literals { +namespace simdutf { +namespace literals { namespace detail { @@ -13192,9 +14088,7 @@ namespace detail { template struct base64_literal_helper { std::array storage{}; - static constexpr auto size() noexcept -> std::size_t { - return N - 1; - } + static constexpr std::size_t size() noexcept { return N - 1; } consteval base64_literal_helper(const char (&str)[N]) { for (std::size_t i = 0; i < size(); i++) { storage[i] = str[i]; @@ -13203,9 +14097,9 @@ template struct base64_literal_helper { }; template struct base64_decode_result { - static constexpr std::size_t maxOut = (InputLen + 3) / 4 * 3; - std::array buffer{}; - std::size_t outputCount{}; + static constexpr std::size_t max_out = (InputLen + 3) / 4 * 3; + std::array buffer{}; + std::size_t output_count{}; }; template @@ -13246,7 +14140,8 @@ template consteval auto operator""_base64() { return detail::base64_make_array(); } -} // namespace simdutf::literals +} // namespace literals +} // namespace simdutf #endif // SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64 @@ -13262,4 +14157,4 @@ template consteval auto operator""_base64() { SIMDUTF_POP_DISABLE_WARNINGS #endif // SIMDUTF_H -/* end file include/simdutf.h */ +/* end file include/simdutf.h */ \ No newline at end of file From e835f204a935db22120d1caa0ee42dacff6d9f61 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 23:27:40 +0200 Subject: [PATCH 31/86] Refactor codebase to improve readability, consistency, and robustness: - Replace raw pointer checks with explicit `nullptr` comparisons for clarity. - Standardize variable and function naming with clearer identifiers. - Simplify conditional logic and eliminate redundant code paths. - Use modern C++ constructs such as `std::min`, `std::max`, and scoped locks where applicable. - Replace `auto` in non-obvious contexts with specific types for better type clarity. - Adjust parameter validation logic and structure to ensure stability. - Correct `invoke` function signature to static for appropriate usability. --- .../Platform/Linux/Core/UiDispatcher.Gtk.cpp | 4 +- .../Platform/Linux/Core/WindowCore.Gtk.cpp | 4 +- .../Platform/Linux/Core/WindowEvents.Gtk.cpp | 104 ++++++++++++------ .../Linux/Core/WindowInitialization.Gtk.cpp | 75 ++++++++----- .../Linux/Core/WindowLifecycle.Gtk.cpp | 16 +-- .../Platform/Linux/WebKit/WebKitHost.Gtk.cpp | 86 ++++++++------- .../Linux/WebKit/WebKitMessaging.Gtk.cpp | 5 +- .../Windows/Core/WindowLifecycle.Win32.cpp | 4 +- .../Public/Exports/Exports.Lifecycle.cpp | 2 +- .../Native/Public/Exports/Exports.Tests.cpp | 2 +- .../Native/Public/InfiniFrameWindow.h | 2 +- 11 files changed, 180 insertions(+), 124 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp index 3c98f172e..22b0d7e00 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp @@ -18,7 +18,7 @@ namespace { auto* waitInfo = reinterpret_cast(data); waitInfo->callback(); { - std::lock_guard guard(invokeLockMutex); + std::lock_guard guard(invokeLockMutex); waitInfo->isCompleted = true; } waitInfo->completionNotifier.notify_one(); @@ -31,7 +31,7 @@ void InfiniFrameWindow::Invoke(const ACTION callback) { waitInfo.callback = callback; gdk_threads_add_idle(invokeCallback, &waitInfo); - std::unique_lock uLock(invokeLockMutex); + std::unique_lock uLock(invokeLockMutex); waitInfo.completionNotifier.wait(uLock, [&] { return waitInfo.isCompleted; }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp index f576681ea..a0b0a6b65 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp @@ -11,10 +11,10 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) gtk_init(nullptr, nullptr); notify_init(initParams->Title); - if (initParams->Size != sizeof(InfiniFrameInitParams)) { + if (initParams->StructSize != sizeof(InfiniFrameInitParams)) { GtkWidget* dialog = gtk_message_dialog_new( nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "Initial parameters passed are %i bytes, but expected %lu bytes.", initParams->Size, + "Initial parameters passed are %i bytes, but expected %lu bytes.", initParams->StructSize, sizeof(InfiniFrameInitParams) ); gtk_dialog_run(GTK_DIALOG(dialog)); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp index 1389b8b47..b8e890e7c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp @@ -7,23 +7,33 @@ InfiniFrameDialog* InfiniFrameWindow::GetDialog() const { } void InfiniFrameWindow::AddCustomSchemeName(const AutoStringConst scheme) { - if (scheme) - m_impl->_customSchemeNames.emplace_back(scheme); + if (scheme == nullptr) { + return; + } + + m_impl->_customSchemeNames.emplace_back(scheme); } void InfiniFrameWindow::GetAllMonitors(const GetAllMonitorsCallback callback) const { - if (callback) { - GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(m_impl->_window)); - GdkDisplay* display = gdk_screen_get_display(screen); - int n = gdk_display_get_n_monitors(display); - for (int i = 0; i < n; i++) { - GdkMonitor* monitor = gdk_display_get_monitor(display, i); - Monitor props = {}; - gdk_monitor_get_geometry(monitor, reinterpret_cast(&props.monitor)); - gdk_monitor_get_workarea(monitor, reinterpret_cast(&props.work)); - props.scale = gdk_monitor_get_scale_factor(monitor); - if (!callback(&props)) - break; + if (callback == nullptr) { + return; + } + + GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(m_impl->_window)); + GdkDisplay* display = gdk_screen_get_display(screen); + + const int MonitorCount = gdk_display_get_n_monitors(display); + + for (int i = 0; i < MonitorCount; i++) { + GdkMonitor* monitor = gdk_display_get_monitor(display, i); + + Monitor props = {}; + gdk_monitor_get_geometry(monitor, reinterpret_cast(&props.monitor)); + gdk_monitor_get_workarea(monitor, reinterpret_cast(&props.work)); + props.scale = gdk_monitor_get_scale_factor(monitor); + + if (callback(&props) == 0) { + break; } } } @@ -65,49 +75,75 @@ void InfiniFrameWindow::SetMinimizedCallback(const MinimizedCallback callback) { } [[nodiscard]] bool InfiniFrameWindow::InvokeClose() const noexcept { - if (m_impl->_closingCallback) - return m_impl->_closingCallback(); - return false; + if (m_impl->_closingCallback == nullptr) { + return false; + } + + return m_impl->_closingCallback(); } void InfiniFrameWindow::InvokeClosed() const noexcept { - if (m_impl->_closedCallback) - m_impl->_closedCallback(); + if (m_impl->_closedCallback == nullptr) { + return; + } + + m_impl->_closedCallback(); } void InfiniFrameWindow::InvokeFocusIn() const noexcept { - if (m_impl->_focusInCallback) - m_impl->_focusInCallback(); + if (m_impl->_focusInCallback == nullptr) { + return; + } + + m_impl->_focusInCallback(); } void InfiniFrameWindow::InvokeFocusOut() const noexcept { - if (m_impl->_focusOutCallback) - m_impl->_focusOutCallback(); + if (m_impl->_focusOutCallback == nullptr) { + return; + } + + m_impl->_focusOutCallback(); } void InfiniFrameWindow::InvokeMove(int x, int y) const noexcept { - if (m_impl->_movedCallback) - m_impl->_movedCallback(x, y); + if (m_impl->_movedCallback == nullptr) { + return; + } + + m_impl->_movedCallback(x, y); } void InfiniFrameWindow::InvokeResize(int width, int height) const noexcept { - if (m_impl->_resizedCallback) - m_impl->_resizedCallback(width, height); + if (m_impl->_resizedCallback == nullptr) { + return; + } + + m_impl->_resizedCallback(width, height); } void InfiniFrameWindow::InvokeMaximized() const noexcept { - if (m_impl->_maximizedCallback) - m_impl->_maximizedCallback(); + if (m_impl->_maximizedCallback == nullptr) { + return; + } + + m_impl->_maximizedCallback(); } void InfiniFrameWindow::InvokeRestored() const noexcept { - if (m_impl->_restoredCallback) - m_impl->_restoredCallback(); + if (m_impl->_restoredCallback == nullptr) { + return; + } + + m_impl->_restoredCallback(); } void InfiniFrameWindow::InvokeMinimized() const noexcept { - if (m_impl->_minimizedCallback) - m_impl->_minimizedCallback(); + if (m_impl->_minimizedCallback == nullptr) { + return; + } + + m_impl->_minimizedCallback(); } -#endif +#endif \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp index 677676b85..4220dca51 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp @@ -1,5 +1,6 @@ #ifdef __linux__ +#include #include #include "../../../Public/InfiniFrameDialog.h" @@ -21,18 +22,27 @@ gboolean on_webview_context_menu( gboolean on_permission_request(WebKitWebView* web_view, WebKitPermissionRequest* request, gpointer user_data); void InfiniFrameWindow::Impl::InitializeFromParams(const InfiniFrameInitParams* initParams) { - _windowTitle = initParams->Title ? initParams->Title : ""; + if (initParams->Title != nullptr) { + _windowTitle = initParams->Title; + } else { + _windowTitle = ""; + } - if (initParams->StartUrl != nullptr) + if (initParams->StartUrl != nullptr) { _startUrl = initParams->StartUrl; - if (initParams->StartString != nullptr) + } + if (initParams->StartString != nullptr) { _startString = initParams->StartString; - if (initParams->TemporaryFilesPath != nullptr) + } + if (initParams->TemporaryFilesPath != nullptr) { _temporaryFilesPath = initParams->TemporaryFilesPath; - if (initParams->UserAgent != nullptr) + } + if (initParams->UserAgent != nullptr) { _userAgent = initParams->UserAgent; - if (initParams->BrowserControlInitParameters != nullptr) + } + if (initParams->BrowserControlInitParameters != nullptr) { _browserControlInitParameters = initParams->BrowserControlInitParameters; + } _transparentEnabled = initParams->Transparent; _contextMenuEnabled = initParams->ContextMenuEnabled; @@ -67,9 +77,11 @@ void InfiniFrameWindow::Impl::InitializeFromParams(const InfiniFrameInitParams* _customSchemeCallback = initParams->CustomSchemeHandler; _customSchemeNames.clear(); - for (int i = 0; i < 16; ++i) { - if (initParams->CustomSchemeNames[i] != nullptr) - _customSchemeNames.emplace_back(initParams->CustomSchemeNames[i]); + for (auto* customSchemeName : initParams->CustomSchemeNames) { + if (customSchemeName == nullptr) { + continue; + } + _customSchemeNames.emplace_back(customSchemeName); } _parent = initParams->ParentInstance; @@ -84,29 +96,27 @@ void InfiniFrameWindow::Impl::ConfigureInitialWindow(InfiniFrameWindow* window, return; } - if (initParams->Width > initParams->MaxWidth) - initParams->Width = initParams->MaxWidth; - if (initParams->Height > initParams->MaxHeight) - initParams->Height = initParams->MaxHeight; - if (initParams->Width < initParams->MinWidth) - initParams->Width = initParams->MinWidth; - if (initParams->Height < initParams->MinHeight) - initParams->Height = initParams->MinHeight; + initParams->Width = std::min(initParams->Width, initParams->MaxWidth); + initParams->Height = std::min(initParams->Height, initParams->MaxHeight); + initParams->Width = std::max(initParams->Width, initParams->MinWidth); + initParams->Height = std::max(initParams->Height, initParams->MinHeight); - if (initParams->UseOsDefaultSize) + if (initParams->UseOsDefaultSize) { gtk_window_set_default_size(GTK_WINDOW(_window), -1, -1); - else + } else { gtk_window_set_default_size(GTK_WINDOW(_window), initParams->Width, initParams->Height); + } window->SetMinSize(initParams->MinWidth, initParams->MinHeight); window->SetMaxSize(initParams->MaxWidth, initParams->MaxHeight); - if (initParams->UseOsDefaultLocation) + if (initParams->UseOsDefaultLocation) { gtk_window_set_position(GTK_WINDOW(_window), GTK_WIN_POS_NONE); - else if (initParams->CenterOnInitialize) + } else if (initParams->CenterOnInitialize) { gtk_window_set_position(GTK_WINDOW(_window), GTK_WIN_POS_CENTER); - else + } else { gtk_window_move(GTK_WINDOW(_window), initParams->Left, initParams->Top); + } } void InfiniFrameWindow::Impl::ApplyInitialWindowState( @@ -114,22 +124,29 @@ void InfiniFrameWindow::Impl::ApplyInitialWindowState( ) { window->SetTitle(const_cast(_windowTitle.c_str())); - if (initParams->Chromeless) + if (initParams->Chromeless) { gtk_window_set_decorated(GTK_WINDOW(_window), false); + } - if (initParams->WindowIconFile != nullptr && std::strlen(initParams->WindowIconFile) > 0) + if (initParams->WindowIconFile != nullptr && std::strlen(initParams->WindowIconFile) > 0) { window->SetIconFile(initParams->WindowIconFile); + } - if (initParams->CenterOnInitialize) + if (initParams->CenterOnInitialize) { window->Center(); - if (initParams->Minimized) + } + if (initParams->Minimized) { window->SetMinimized(true); - if (initParams->Maximized) + } + if (initParams->Maximized) { window->SetMaximized(true); - if (!initParams->Resizable) + } + if (!initParams->Resizable) { window->SetResizable(false); - if (initParams->Topmost) + } + if (initParams->Topmost) { window->SetTopmost(true); + } } void InfiniFrameWindow::Impl::ConnectWindowSignals(InfiniFrameWindow* window) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp index 6c1b03c5a..270372442 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp @@ -8,10 +8,10 @@ void InfiniFrameWindow::Center() { gint windowWidth, windowHeight; gtk_window_get_size(GTK_WINDOW(m_impl->_window), &windowWidth, &windowHeight); - GdkRectangle screen = {0}; + GdkRectangle screen = {}; - GdkDisplay* d = gdk_display_get_default(); - if (d == nullptr) { + GdkDisplay* display = gdk_display_get_default(); + if (display == nullptr) { GtkWidget* dialog = gtk_message_dialog_new( nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "gdk_display_get_default() returned NULL" @@ -21,10 +21,10 @@ void InfiniFrameWindow::Center() { return; } - GdkMonitor* m = gdk_display_get_primary_monitor(d); - if (m == nullptr) { - m = gdk_display_get_monitor(d, 0); - if (m == nullptr) { + GdkMonitor* monitor = gdk_display_get_primary_monitor(display); + if (monitor == nullptr) { + monitor = gdk_display_get_monitor(display, 0); + if (monitor == nullptr) { GtkWidget* dialog = gtk_message_dialog_new( nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "gdk_display_get_primary_monitor() returned NULL" @@ -35,7 +35,7 @@ void InfiniFrameWindow::Center() { } } - gdk_monitor_get_geometry(m, &screen); + gdk_monitor_get_geometry(monitor, &screen); gtk_window_move(GTK_WINDOW(m_impl->_window), (screen.width - windowWidth) / 2, (screen.height - windowHeight) / 2); } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp index ece2fbfc6..23ac98077 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp @@ -17,57 +17,59 @@ extern void on_webview_process_terminated( extern void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpointer user_data); void InfiniFrameWindow::Show(bool isAlreadyShown) { - if (!m_impl->_webview) { - struct sigaction old_action; - sigaction(SIGCHLD, nullptr, &old_action); - WebKitUserContentManager* contentManager = webkit_user_content_manager_new(); - m_impl->_webview = webkit_web_view_new_with_user_content_manager(contentManager); + if (m_impl->_webview) { + return; + } - m_impl->set_webkit_settings(); + struct sigaction oldAction{}; + sigaction(SIGCHLD, nullptr, &oldAction); + WebKitUserContentManager* contentManager = webkit_user_content_manager_new(); + m_impl->_webview = webkit_web_view_new_with_user_content_manager(contentManager); - gtk_container_add(GTK_CONTAINER(m_impl->_window), m_impl->_webview); - gtk_widget_set_hexpand(m_impl->_webview, TRUE); - gtk_widget_set_vexpand(m_impl->_webview, TRUE); + m_impl->set_webkit_settings(); - auto js = Embedded::InfiniFrameJsUtf8(); + gtk_container_add(GTK_CONTAINER(m_impl->_window), m_impl->_webview); + gtk_widget_set_hexpand(m_impl->_webview, TRUE); + gtk_widget_set_vexpand(m_impl->_webview, TRUE); - WebKitUserScript* script = webkit_user_script_new( - js.c_str(), WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, nullptr, - nullptr - ); + const auto& jsCode = Embedded::InfiniFrameJsUtf8(); - webkit_user_content_manager_add_script(contentManager, script); - webkit_user_script_unref(script); + WebKitUserScript* script = webkit_user_script_new( + jsCode.c_str(), WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, nullptr, + nullptr + ); - g_signal_connect( - contentManager, "script-message-received::infiniFrameInterop", G_CALLBACK(gtk_webkit::HandleWebMessage), - reinterpret_cast(m_impl->_webMessageReceivedCallback) - ); - webkit_user_content_manager_register_script_message_handler(contentManager, "infiniFrameInterop"); + webkit_user_content_manager_add_script(contentManager, script); + webkit_user_script_unref(script); + + g_signal_connect( + contentManager, "script-message-received::infiniFrameInterop", G_CALLBACK(gtk_webkit::HandleWebMessage), + reinterpret_cast(m_impl->_webMessageReceivedCallback) + ); + webkit_user_content_manager_register_script_message_handler(contentManager, "infiniFrameInterop"); + + g_signal_connect(G_OBJECT(m_impl->_webview), "load-changed", G_CALLBACK(on_webview_load_changed), this); + g_signal_connect(G_OBJECT(m_impl->_webview), "load-failed", G_CALLBACK(on_webview_load_failed), this); + g_signal_connect( + G_OBJECT(m_impl->_webview), "web-process-terminated", G_CALLBACK(on_webview_process_terminated), this + ); + g_signal_connect(G_OBJECT(m_impl->_webview), "size-allocate", G_CALLBACK(on_webview_size_allocate), this); - g_signal_connect(G_OBJECT(m_impl->_webview), "load-changed", G_CALLBACK(on_webview_load_changed), this); - g_signal_connect(G_OBJECT(m_impl->_webview), "load-failed", G_CALLBACK(on_webview_load_failed), this); - g_signal_connect( - G_OBJECT(m_impl->_webview), "web-process-terminated", G_CALLBACK(on_webview_process_terminated), this + if (!m_impl->_startUrl.empty()) { + NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); + } else if (!m_impl->_startString.empty()) { + NavigateToString(const_cast(m_impl->_startString.c_str())); + } else { + GtkWidget* dialog = gtk_message_dialog_new( + nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "Neither StartUrl nor StartString was specified" ); - g_signal_connect(G_OBJECT(m_impl->_webview), "size-allocate", G_CALLBACK(on_webview_size_allocate), this); - - if (!m_impl->_startUrl.empty()) - NavigateToUrl(const_cast(m_impl->_startUrl.c_str())); - else if (!m_impl->_startString.empty()) - NavigateToString(const_cast(m_impl->_startString.c_str())); - else { - GtkWidget* dialog = gtk_message_dialog_new( - nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "Neither StartUrl nor StartString was specified" - ); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - sigaction(SIGCHLD, &old_action, nullptr); - return; - } - sigaction(SIGCHLD, &old_action, nullptr); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + sigaction(SIGCHLD, &oldAction, nullptr); + return; } + sigaction(SIGCHLD, &oldAction, nullptr); gtk_widget_show_all(m_impl->_window); } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp index 274f47d76..7749628c6 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp @@ -3,7 +3,8 @@ #include #include -#include "../../../Utils/Common.h" +#include "Types/Basic.h" +#include "Types/Callbacks.h" #include "WebKit.Gtk.Internal.h" namespace gtk_webkit { @@ -13,7 +14,7 @@ namespace gtk_webkit { JSCValue* jsValue = webkit_javascript_result_get_js_value(jsResult); if (jsc_value_is_string(jsValue)) { AutoString str_value = jsc_value_to_string(jsValue); - WebMessageReceivedCallback callback = reinterpret_cast(userData); + auto callback = reinterpret_cast(userData); AutoString originValue = nullptr; JSGlobalContextRef context = webkit_javascript_result_get_global_context(jsResult); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp index 3a0d470b3..eccbb3ccb 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp @@ -77,9 +77,9 @@ void InfiniFrameWindow::Register(const HINSTANCE hInstance) { InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { m_impl = std::make_unique(); - if (initParams->Size != sizeof(InfiniFrameInitParams)) { + if (initParams->StructSize != sizeof(InfiniFrameInitParams)) { auto msg = std::format( - L"Initial parameters passed are {} bytes, but expected {} bytes.", initParams->Size, + L"Initial parameters passed are {} bytes, but expected {} bytes.", initParams->StructSize, sizeof(InfiniFrameInitParams) ); MessageBox(nullptr, msg.c_str(), L"Native Initialization Failed", MB_OK); diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp index b05352241..00d065b0a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp @@ -8,7 +8,7 @@ EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, Infin return; if (initParams == nullptr) throw std::invalid_argument("Argument 'initParams' is null."); - if (initParams->Size != static_cast(sizeof(InfiniFrameInitParams))) { + if (initParams->StructSize != static_cast(sizeof(InfiniFrameInitParams))) { throw std::invalid_argument("InfiniFrameInitParams.Size does not match native struct size."); } auto instance = std::make_unique(initParams); diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp index 4e9b5a0fb..b6b23d826 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp @@ -106,7 +106,7 @@ EXPORTED InteropStatus InfiniFrameNativeTests_NativeParametersReturnAsIs( (*new_params)->SmoothScrollingEnabled = params->SmoothScrollingEnabled; (*new_params)->IgnoreCertificateErrorsEnabled = params->IgnoreCertificateErrorsEnabled; (*new_params)->NotificationsEnabled = params->NotificationsEnabled; - (*new_params)->Size = params->Size; + (*new_params)->StructSize = params->StructSize; }); } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h index d149419b5..792fd8742 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h @@ -471,7 +471,7 @@ class InfiniFrameWindow { * @brief Marshal a callback onto the UI thread and execute it synchronously * @param callback Action to invoke on the UI thread */ - void Invoke(ACTION callback); + static void Invoke(ACTION callback); /** * @brief Fire the closing callback From 16eb72c11171e40f573961fd005d4cefd149698d Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Sun, 17 May 2026 23:43:29 +0200 Subject: [PATCH 32/86] Refactor `InfiniFrameWindow` and `UiDispatcher.Win32` to improve pointer handling, fix `Invoke` function signature, and enhance code readability. --- .../Windows/Core/UiDispatcher.Win32.cpp | 21 +++++++++++-------- .../Native/Public/InfiniFrameWindow.h | 4 ++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp index e4ac702b7..142b8c069 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp @@ -1,12 +1,12 @@ -#include - +#include "chrono" #include "../Window.Win32.Context.h" void InfiniFrameWindow::WaitForExit() { - ApplyPendingOwnerWindow(m_impl.get(), L"wait_for_exit"); + auto* impl = m_impl.get(); + ApplyPendingOwnerWindow(impl, L"wait_for_exit"); - messageLoopRootWindowHandle = m_impl->_hWnd; - TraceTeardown(L"WaitForExit start instance=%p hwnd=%p", this, m_impl->_hWnd); + messageLoopRootWindowHandle = impl->_hWnd; + TraceTeardown(L"WaitForExit start instance=%p hwnd=%p", this, impl->_hWnd); MSG msg = {}; while (true) { @@ -23,19 +23,22 @@ void InfiniFrameWindow::WaitForExit() { } messageLoopRootWindowHandle = nullptr; - TraceTeardown(L"WaitForExit end instance=%p hwnd=%p", this, m_impl->_hWnd); + TraceTeardown(L"WaitForExit end instance=%p hwnd=%p", this, impl->_hWnd); } void InfiniFrameWindow::Invoke(ACTION callback) { - if (!callback) + if (!callback) { return; + } - if (m_impl->_hWnd == nullptr || !IsWindow(m_impl->_hWnd)) + auto* impl = m_impl.get(); + if (impl->_hWnd == nullptr || IsWindow(impl->_hWnd) == 0) { return; + } auto* waitInfo = new InvokeWaitInfo(); if (!PostMessage( - m_impl->_hWnd, WM_USER_INVOKE, reinterpret_cast(callback), reinterpret_cast(waitInfo) + impl->_hWnd, WM_USER_INVOKE, reinterpret_cast(callback), reinterpret_cast(waitInfo) )) { delete waitInfo; return; diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h index 792fd8742..86ae9cbfd 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h @@ -471,7 +471,7 @@ class InfiniFrameWindow { * @brief Marshal a callback onto the UI thread and execute it synchronously * @param callback Action to invoke on the UI thread */ - static void Invoke(ACTION callback); + void Invoke(ACTION callback); /** * @brief Fire the closing callback @@ -595,4 +595,4 @@ class InfiniFrameWindow { std::unique_ptr m_impl; }; -#include "InfiniFrameInitParams.h" \ No newline at end of file +#include "InfiniFrameInitParams.h" From 8d872c62b178b6eb4c212e691470badd6104ffea Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 11:26:05 +0200 Subject: [PATCH 33/86] Refactor `Platform.MacOS.cmake` to support common and test sources, and update macOS configuration in `CMakeLists.txt`. --- .../Native/.cmake/Platform.MacOS.cmake | 16 ++++++++++------ .../Native/CMakeLists.txt | 2 ++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake index 8be141301..803b39292 100644 --- a/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake +++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake @@ -1,19 +1,23 @@ # Configure the macOS native target. # Params: # - target_name: final CMake target name (usually `${PROJECT_NAME}`) +# - common_sources: list of cross-platform source files +# - test_sources: list of test/helper source files compiled into the native target # - mac_sources: list of macOS-only source files # - header_files: list of header files for IDE organization -function(infiniframe_configure_macos_target target_name mac_sources header_files) - configure_file(Exports.cpp ${CMAKE_CURRENT_BINARY_DIR}/Exports.mm COPYONLY) - configure_file(Exports.Tests.cpp ${CMAKE_CURRENT_BINARY_DIR}/Exports.Tests.mm COPYONLY) - +function(infiniframe_configure_macos_target target_name common_sources test_sources mac_sources header_files) add_library(${target_name} SHARED - ${CMAKE_CURRENT_BINARY_DIR}/Exports.mm - ${CMAKE_CURRENT_BINARY_DIR}/Exports.Tests.mm + ${common_sources} + ${test_sources} ${mac_sources} ${header_files} ) + # Export units include platform headers that require Objective-C++ on macOS. + set_source_files_properties(${common_sources} ${test_sources} PROPERTIES + LANGUAGE OBJCXX + ) + target_include_directories(${target_name} PRIVATE "${CMAKE_SOURCE_DIR}") set_target_properties(${target_name} PROPERTIES diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index ca674d2d2..a0cd1e70b 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -148,6 +148,8 @@ if (WIN32) elseif (APPLE) infiniframe_configure_macos_target( ${PROJECT_NAME} + "${COMMON_SOURCES}" + "${TEST_SOURCES}" "${MAC_SOURCES}" "${HEADER_FILES}" ) From 9f039a87d24cb77ff5ed92c3a50da13b7866f6db Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 11:34:02 +0200 Subject: [PATCH 34/86] Refactor macOS build configuration: update architecture handling, improve target compile options, enable `OBJ-C++`, and streamline Debug sanitizer setup. --- .../Native/.cmake/Platform.MacOS.cmake | 6 ++-- .../Native/CMakeLists.txt | 33 ++++++++++--------- src/InfiniFrame.NativeBridge/native-build.ps1 | 12 ++++++- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake index 803b39292..90f94f39d 100644 --- a/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake +++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake @@ -24,7 +24,6 @@ function(infiniframe_configure_macos_target target_name common_sources test_sour PREFIX "" OUTPUT_NAME "InfiniFrame.Native" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" - OSX_ARCHITECTURES "x86_64;arm64" ) target_link_libraries(${target_name} PRIVATE @@ -38,7 +37,10 @@ function(infiniframe_configure_macos_target target_name common_sources test_sour target_compile_options(${target_name} PRIVATE -Wall -Wextra - -O2 + $<$:-O0 -g> + $<$:-O2> + $<$:-O2 -g> + $<$:-Os> -fPIC ) endfunction() diff --git a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt index a0cd1e70b..b3ffb5c9e 100644 --- a/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt +++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt @@ -5,16 +5,19 @@ project(InfiniFrame.Native DESCRIPTION "InfiniFrame.Native webview-wrapper library" ) +if (APPLE) + enable_language(OBJCXX) +endif () + set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_OBJCXX_STANDARD 23) +set(CMAKE_OBJCXX_STANDARD_REQUIRED ON) +set(CMAKE_OBJCXX_EXTENSIONS OFF) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") -if (APPLE) - set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "" FORCE) -endif () - # ---------------------------------------------------------------------------------------------------------------------- # Dependencies # ---------------------------------------------------------------------------------------------------------------------- @@ -180,18 +183,16 @@ endif () # ---------------------------------------------------------------------------------------------------------------------- # Sanitizers (Debug only) # ---------------------------------------------------------------------------------------------------------------------- -if (CMAKE_BUILD_TYPE STREQUAL "Debug") - if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") - message(STATUS "Enabling sanitizers for Debug build") - target_compile_options(${PROJECT_NAME} PRIVATE - -fsanitize=address,undefined,leak - -fno-omit-frame-pointer - -fno-optimize-sibling-calls - ) - target_link_options(${PROJECT_NAME} PRIVATE - -fsanitize=address,undefined,leak - ) - endif () +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + message(STATUS "Enabling sanitizers for Debug configuration") + target_compile_options(${PROJECT_NAME} PRIVATE + $<$:-fsanitize=address,undefined,leak> + $<$:-fno-omit-frame-pointer> + $<$:-fno-optimize-sibling-calls> + ) + target_link_options(${PROJECT_NAME} PRIVATE + $<$:-fsanitize=address,undefined,leak> + ) endif () # ---------------------------------------------------------------------------------------------------------------------- diff --git a/src/InfiniFrame.NativeBridge/native-build.ps1 b/src/InfiniFrame.NativeBridge/native-build.ps1 index 7bdfc5489..4027ce498 100644 --- a/src/InfiniFrame.NativeBridge/native-build.ps1 +++ b/src/InfiniFrame.NativeBridge/native-build.ps1 @@ -78,9 +78,19 @@ try { if ($Platform -eq "osx") { if ($Arch -eq "arm64") { $CMakeArgs += "-DCMAKE_OSX_ARCHITECTURES=arm64" - } else { + } + elseif ($Arch -eq "x64") { $CMakeArgs += "-DCMAKE_OSX_ARCHITECTURES=x86_64" } + else { + throw "Unsupported macOS architecture '$Arch'. Expected 'x64' or 'arm64'." + } + } + + if ($Platform -eq "linux") { + if ($Arch -ne "x64" -and $Arch -ne "arm64") { + throw "Unsupported Linux architecture '$Arch'. Expected 'x64' or 'arm64'." + } } if ($Platform -eq "windows") { From 4357058ba57978fb497be906ff86109a083bebc6 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 11:34:08 +0200 Subject: [PATCH 35/86] Comment out `#if/#else` block in `InfiniFrameNativeTesting.cs` to disable platform-specific code paths. --- .../InfiniFrameNativeTesting.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs index 96606950f..cb545f853 100644 --- a/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs +++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs @@ -12,7 +12,7 @@ namespace InfiniFrame.NativeBridge; // Code // --------------------------------------------------------------------------------------------------------------------- public static partial class InfiniFrameNativeTesting { -#if InfiniFrameNativeTestExports +// #if InfiniFrameNativeTestExports [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrameNativeTests_NativeParametersReturnAsIs", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] private static partial InfiniFrameNativeInteropStatus NativeParametersReturnAsIsNative( [MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))] @@ -45,15 +45,15 @@ internal static void FreeInitParams(IntPtr newParametersPtr) { FreeInitParamsNative(newParametersPtr), nameof(FreeInitParamsNative)); } -#else - internal static IntPtr NativeParametersReturnAsIsPtr(ref InfiniFrameNativeParameters parameters) { - throw new PlatformNotSupportedException("InfiniFrame native test exports are not enabled for this build."); - } - - internal static void FreeInitParams(IntPtr newParametersPtr) { - if (newParametersPtr != IntPtr.Zero) { - throw new PlatformNotSupportedException("InfiniFrame native test exports are not enabled for this build."); - } - } -#endif +// #else +// internal static IntPtr NativeParametersReturnAsIsPtr(ref InfiniFrameNativeParameters parameters) { +// throw new PlatformNotSupportedException("InfiniFrame native test exports are not enabled for this build."); +// } +// +// internal static void FreeInitParams(IntPtr newParametersPtr) { +// if (newParametersPtr != IntPtr.Zero) { +// throw new PlatformNotSupportedException("InfiniFrame native test exports are not enabled for this build."); +// } +// } +// #endif } From 167a65199ceb7775f57676fc8e6dbdd107188cbc Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 11:38:37 +0200 Subject: [PATCH 36/86] Refactor macOS codebase: add explicit `(void)` casts for unused parameters and include missing `` header in `Embedded.h`. --- src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h | 1 + .../Native/Platform/Mac/Core/WindowLifecycle.Cocoa.mm | 4 +++- .../Native/Platform/Mac/UiDelegate.mm | 1 + .../Native/Platform/Mac/WebKit/WebKitHost.Cocoa.mm | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h index f123dcebb..d5aa79e48 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h @@ -2,6 +2,7 @@ #include "InfiniFrameJs.h" #include +#include namespace Embedded { inline const std::wstring& InfiniFrameJsUtf16() { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowLifecycle.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowLifecycle.Cocoa.mm index 20e1e9f36..8bb671e17 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowLifecycle.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Core/WindowLifecycle.Cocoa.mm @@ -42,7 +42,9 @@ content: objNotificationContent trigger: trigger]; UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - [center addNotificationRequest: request withCompletionHandler: ^(NSError * _Nullable error) {}]; + [center addNotificationRequest: request withCompletionHandler: ^(NSError * _Nullable error) { + (void)error; + }]; } void InfiniFrameWindow::WaitForExit() diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.mm index 525cd055d..0e0ab8023 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.mm @@ -35,6 +35,7 @@ - (void)webView:(WKWebView *)webView [alert addButtonWithTitle:@"OK"]; [alert beginSheetModalForWindow:window completionHandler:^void (NSModalResponse response) { + (void)response; completionHandler(); [alert release]; }]; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitHost.Cocoa.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitHost.Cocoa.mm index 44f01e90c..e06e6f23a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitHost.Cocoa.mm +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WebKit/WebKitHost.Cocoa.mm @@ -59,6 +59,8 @@ void InfiniFrameWindow::Show(bool isAlreadyShown) { + (void)isAlreadyShown; + if (m_impl->_webview == nil) AttachWebView(); From d7bd42302c11ee5a86ee6400ae0665d8b0cbbbda Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 11:45:38 +0200 Subject: [PATCH 37/86] Extend `clean.ps1` to remove additional build artifacts and node_modules. --- .gitignore | 3 +++ scripts/clean.ps1 | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8ed5b2ad8..e7eadd063 100644 --- a/.gitignore +++ b/.gitignore @@ -351,6 +351,9 @@ healthchecksdb /src/InfiniFrame.NativeBridge/Native/cmake-build-debug/ /src/InfiniFrame.NativeBridge/Native/cmake-build-debug-linux/ /src/InfiniFrame.NativeBridge/Native/cmake-build-debug-windows/ +/src/InfiniFrame.NativeBridge/Native/cmake-build-release/ +/src/InfiniFrame.NativeBridge/Native/cmake-build-release-linux/ +/src/InfiniFrame.NativeBridge/Native/cmake-build-release-windows/ /src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.cpp # wwwroot folders from js web based projects diff --git a/scripts/clean.ps1 b/scripts/clean.ps1 index b15dede17..292fdef01 100644 --- a/scripts/clean.ps1 +++ b/scripts/clean.ps1 @@ -10,4 +10,25 @@ Get-ChildItem -Path $Root -Directory -Recurse | Remove-Item $_.FullName -Recurse -Force -ErrorAction SilentlyContinue } -Write-Host "Done cleaning bin/obj folders." \ No newline at end of file +# Additional cleanup paths +$ExtraPaths = @( + "../src/InfiniFrame.NativeBridge/build", + "../src/InfiniFrame.NativeBridge/artifacts", + "../src/InfiniFrame.Js/node_modules", + "../src/InfiniFrame.NativeBridge/Native/cmake-build-debug-linux", + "../src/InfiniFrame.NativeBridge/Native/cmake-build-debug-windows", + "../src/InfiniFrame.NativeBridge/Native/cmake-build-release-linux", + "../src/InfiniFrame.NativeBridge/Native/cmake-build-release-windows", + "../src/InfiniFrame.NativeBridge/Native/packages" +) + +foreach ($RelativePath in $ExtraPaths) { + $FullPath = Join-Path $Root $RelativePath + + if (Test-Path $FullPath) { + Write-Host "Deleting $FullPath" + Remove-Item $FullPath -Recurse -Force -ErrorAction SilentlyContinue + } +} + +Write-Host "Done cleaning bin/obj folders and extra build artifacts." \ No newline at end of file From 7413d3e9505d8b3ff9ecb30c4436fa201b14c02b Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 11:51:03 +0200 Subject: [PATCH 38/86] Update `.gitattributes` to reflect new `NativeBridge` folder structure --- .gitattributes | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 10cf9919c..b7f18b462 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ -src/InfiniFrame.Native/Dependencies/* linguist-vendored -src/InfiniFrame.Native/Dependencies/**/* linguist-vendored +src/InfiniFrame.NativeBridge/Native/Dependencies/* linguist-vendored +src/InfiniFrame.NativeBridge/Native/Dependencies/**/* linguist-vendored *.sh text eol=lf \ No newline at end of file From 79fa3531c903b76928e0dee5a4efdfbd4e027fbd Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:05:27 +0200 Subject: [PATCH 39/86] Refactor `InfiniFrame_GetLastErrorMessage` to improve exception handling, parameter validation, and robustness. --- .../Native/Public/Exports/Exports.Memory.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp index 584242e46..582c48eb0 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp @@ -38,10 +38,17 @@ EXPORTED InteropStatus InfiniFrame_FreeStringArray(AutoString* values, const int EXPORTED InteropStatus InfiniFrame_GetLastErrorMessage(AutoString* value) { ResetOut(value, static_cast(nullptr)); - return RunExportStatus([&] { - if (!EnsureOutNotNull(value, "value")) - return; + if (!EnsureOutNotNull(value, "value")) + return InteropStatus::OutParameterSetToInvalidNull; + + try { *value = GetLastErrorMessageCopy(); - }); + return InteropStatus::Success; + } catch (const std::exception& ex) { + return infiniframe::exports::detail::TranslateException(ex); + } catch (...) { + infiniframe::exports::detail::SetFailure(InteropStatus::OperationFailed, "Unknown native exception."); + return InteropStatus::OperationFailed; + } } } From 6c13e27898a182fb51ffc5fe5ccd4dc8849e75c1 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:06:30 +0200 Subject: [PATCH 40/86] Update `clion-linux-environment.sh` to install Node.js 24, include `curl` dependency, and display Node/NPM versions --- scripts/clion-linux-environment.sh | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/scripts/clion-linux-environment.sh b/scripts/clion-linux-environment.sh index fa0062915..15e2b390a 100644 --- a/scripts/clion-linux-environment.sh +++ b/scripts/clion-linux-environment.sh @@ -11,10 +11,23 @@ sudo apt install -y \ gnupg \ software-properties-common \ wget \ + curl \ build-essential \ pkg-config \ - lsb-release \ - nodejs + lsb-release + +# ---------------------------------------------------------------------------------------------------------------------- +# Node.js 24 +# ---------------------------------------------------------------------------------------------------------------------- +echo "Installing Node.js 24..." + +curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash - + +sudo apt install -y nodejs + +echo "Node version:" +node --version +npm --version # ---------------------------------------------------------------------------------------------------------------------- # CMake (latest via Kitware) @@ -107,6 +120,12 @@ echo "Verifying toolchain..." echo "CMake version:" cmake --version +echo "Node version:" +node --version + +echo "NPM version:" +npm --version + echo "GCC version:" gcc --version || true From acdeab689d609a0fba0ffcde45860705195c5ae3 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:08:32 +0200 Subject: [PATCH 41/86] Update CodeQL workflow to reflect new `NativeBridge` folder structure --- .github/workflows/ci-codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml index ff402c488..6ce2485eb 100644 --- a/.github/workflows/ci-codeql.yml +++ b/.github/workflows/ci-codeql.yml @@ -73,7 +73,7 @@ jobs: - '.github/codeql-config.yml' cpp: - - 'src/InfiniFrame.Native/**' + - 'src/InfiniFrame.NativeBridge/Native/**' - 'native-vendor-deps.json' - 'global.json' - '.github/actions/setup-dependencies-native/**' From 8a08da1de3db472471d18c5845fae1b4a8202e18 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:13:19 +0200 Subject: [PATCH 42/86] Remove redundant `#noinspection` comments from GitHub Actions workflows. --- .github/workflows/ci-codeql.yml | 1 + .github/workflows/ci-release-docs.yml | 2 +- .github/workflows/ci-release.yml | 7 +------ .github/workflows/ci-testing-python.yml | 2 +- .github/workflows/ci-testing.yml | 3 +-- .github/workflows/ci-todo.yml | 1 + .github/workflows/ci-update-native-vendor-deps.yml | 1 + .github/workflows/shared-release-build.yml | 3 +-- .github/workflows/shared-release-bump-version.yml | 1 + .github/workflows/shared-release-publish-docs.yml | 1 + .github/workflows/shared-release-publish.yml | 3 +-- .github/workflows/shared-testing-build.yml | 1 + .github/workflows/shared-testing-docs.yml | 5 +---- .github/workflows/shared-testing-dotnetpack.yml | 3 +-- .github/workflows/shared-testing-js.yml | 3 +-- .github/workflows/shared-testing-linux.yml | 7 +------ .github/workflows/shared-testing-macos.yml | 7 +------ .github/workflows/shared-testing-python.yml | 1 + .../workflows/shared-testing-windows-playwright.yml | 9 +-------- .github/workflows/shared-testing-windows-trim-aot.yml | 7 +------ .github/workflows/shared-testing-windows.yml | 7 +------ .github/workflows/shared-testing.yml | 10 +--------- 22 files changed, 22 insertions(+), 63 deletions(-) diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml index 6ce2485eb..4f027d9bc 100644 --- a/.github/workflows/ci-codeql.yml +++ b/.github/workflows/ci-codeql.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "CodeQL Advanced" concurrency: diff --git a/.github/workflows/ci-release-docs.yml b/.github/workflows/ci-release-docs.yml index d2af5a28f..4f90bfedf 100644 --- a/.github/workflows/ci-release-docs.yml +++ b/.github/workflows/ci-release-docs.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "CI: Release Docs" on: workflow_dispatch: @@ -8,7 +9,6 @@ permissions: id-token: write jobs: - # noinspection UndefinedAction, UndefinedParamsPresent deploy-docs: name: Publish Docs uses: ./.github/workflows/shared-release-publish-docs.yml diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index d9acd393a..1dbc122a3 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "CI: Release" on: workflow_dispatch: @@ -35,12 +36,10 @@ permissions: id-token: write jobs: - # noinspection UndefinedAction tests-python: name: Python Tests uses: ./.github/workflows/shared-testing-python.yml - # noinspection UndefinedAction, UndefinedParamsPresent tests-platform: name: Platform Tests needs: tests-python @@ -60,7 +59,6 @@ jobs: # ------------------------------------------------------------------------------------------------------------------ # Bump version, commit, and tag # ------------------------------------------------------------------------------------------------------------------ - # noinspection UndefinedAction, UndefinedParamsPresent bump-version: name: Bump Version needs: tests-platform @@ -71,7 +69,6 @@ jobs: custom_version: ${{ inputs.custom_version }} secrets: inherit - # noinspection UndefinedAction, UndefinedParamsPresent build: name: Build Native needs: bump-version @@ -80,7 +77,6 @@ jobs: tag_name: ${{ needs.bump-version.outputs.tag_name }} secrets: inherit - # noinspection UndefinedAction, UndefinedParamsPresent publish: name: Publish Release needs: [ build, bump-version ] @@ -91,7 +87,6 @@ jobs: publish_to_nuget: ${{ inputs.publish_to_nuget }} secrets: inherit - # noinspection UndefinedAction, UndefinedParamsPresent publish-docs: name: Publish Docs needs: [ publish, bump-version ] diff --git a/.github/workflows/ci-testing-python.yml b/.github/workflows/ci-testing-python.yml index 6fd79653c..49bf36193 100644 --- a/.github/workflows/ci-testing-python.yml +++ b/.github/workflows/ci-testing-python.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "CI: Python Tests" on: pull_request: @@ -20,7 +21,6 @@ permissions: contents: read jobs: - # noinspection UndefinedAction run: name: Python Tests uses: ./.github/workflows/shared-testing-python.yml diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index e2aa94a49..1ea2c7d9f 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "CI: Full Test Suite" permissions: @@ -38,12 +39,10 @@ on: default: true jobs: - # noinspection UndefinedAction python-tests: name: Python Tests uses: ./.github/workflows/shared-testing-python.yml - # noinspection UndefinedAction, UndefinedParamsPresent run: name: Full Test Suite needs: python-tests diff --git a/.github/workflows/ci-todo.yml b/.github/workflows/ci-todo.yml index f63416fa1..b35132747 100644 --- a/.github/workflows/ci-todo.yml +++ b/.github/workflows/ci-todo.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "CI: Todo Sync" on: push: diff --git a/.github/workflows/ci-update-native-vendor-deps.yml b/.github/workflows/ci-update-native-vendor-deps.yml index 446755bc0..f0eb91c4f 100644 --- a/.github/workflows/ci-update-native-vendor-deps.yml +++ b/.github/workflows/ci-update-native-vendor-deps.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "CI: Update Native Vendor Deps" on: diff --git a/.github/workflows/shared-release-build.yml b/.github/workflows/shared-release-build.yml index 3a8dbe3e1..0f2069225 100644 --- a/.github/workflows/shared-release-build.yml +++ b/.github/workflows/shared-release-build.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Release Build" on: workflow_call: @@ -57,9 +58,7 @@ jobs: 10.x - name: Setup Native dependencies - # noinspection UndefinedAction uses: ./.github/actions/setup-dependencies-native - # noinspection UndefinedParamsPresent with: brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-release-build.yml') }} brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native- diff --git a/.github/workflows/shared-release-bump-version.yml b/.github/workflows/shared-release-bump-version.yml index 9c322cd7b..52c0b5d51 100644 --- a/.github/workflows/shared-release-bump-version.yml +++ b/.github/workflows/shared-release-bump-version.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Release Bump Version" on: workflow_call: diff --git a/.github/workflows/shared-release-publish-docs.yml b/.github/workflows/shared-release-publish-docs.yml index 494bd81d0..904385cb1 100644 --- a/.github/workflows/shared-release-publish-docs.yml +++ b/.github/workflows/shared-release-publish-docs.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Release Docs" on: workflow_call: diff --git a/.github/workflows/shared-release-publish.yml b/.github/workflows/shared-release-publish.yml index 061dc29fe..98869e080 100644 --- a/.github/workflows/shared-release-publish.yml +++ b/.github/workflows/shared-release-publish.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Release Publish" on: workflow_call: @@ -50,9 +51,7 @@ jobs: --prefix InfiniLore - name: Setup Native dependencies - # noinspection UndefinedAction uses: ./.github/actions/setup-dependencies-native - # noinspection UndefinedParamsPresent with: brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-release-publish.yml') }} brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native- diff --git a/.github/workflows/shared-testing-build.yml b/.github/workflows/shared-testing-build.yml index 6abaf4ce9..10bcc7472 100644 --- a/.github/workflows/shared-testing-build.yml +++ b/.github/workflows/shared-testing-build.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Testing Build" on: workflow_call: diff --git a/.github/workflows/shared-testing-docs.yml b/.github/workflows/shared-testing-docs.yml index 8585f0d97..b1c783ead 100644 --- a/.github/workflows/shared-testing-docs.yml +++ b/.github/workflows/shared-testing-docs.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Docs Tests" on: @@ -46,9 +47,7 @@ jobs: - name: Set Docs Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction, UndefinedParamsPresent uses: ./.github/actions/sync-check - # noinspection UndefinedAction, UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ env.TARGET_SHA }} @@ -66,9 +65,7 @@ jobs: if: always() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction, UndefinedParamsPresent uses: ./.github/actions/sync-check-finalize - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ env.TARGET_SHA }} diff --git a/.github/workflows/shared-testing-dotnetpack.yml b/.github/workflows/shared-testing-dotnetpack.yml index 5dd60da02..b379f11b4 100644 --- a/.github/workflows/shared-testing-dotnetpack.yml +++ b/.github/workflows/shared-testing-dotnetpack.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Dotnet Pack Tests" on: @@ -45,9 +46,7 @@ jobs: - name: Set Dotnet Pack Check Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} diff --git a/.github/workflows/shared-testing-js.yml b/.github/workflows/shared-testing-js.yml index 22134c3aa..e0c051bc3 100644 --- a/.github/workflows/shared-testing-js.yml +++ b/.github/workflows/shared-testing-js.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Js Tests" on: @@ -55,9 +56,7 @@ jobs: if: always() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction, UndefinedParamsPresent uses: ./.github/actions/sync-check-finalize - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ env.TARGET_SHA }} diff --git a/.github/workflows/shared-testing-linux.yml b/.github/workflows/shared-testing-linux.yml index 5c112fb8e..607e2f7a5 100644 --- a/.github/workflows/shared-testing-linux.yml +++ b/.github/workflows/shared-testing-linux.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Linux Tests" on: workflow_call: @@ -60,9 +61,7 @@ jobs: - name: Set Linux Check Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} @@ -178,9 +177,7 @@ jobs: -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Pack Tool E2E - # noinspection UndefinedAction uses: ./.github/actions/packtool-e2e - # noinspection UndefinedParamsPresent with: project: examples/InfiniFrameExample.SingleFileExe/InfiniFrameExample.SingleFileExe.csproj rid: ${{ matrix.rid }} @@ -197,9 +194,7 @@ jobs: if: always() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction, UndefinedParamsPresent uses: ./.github/actions/sync-check-finalize - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} diff --git a/.github/workflows/shared-testing-macos.yml b/.github/workflows/shared-testing-macos.yml index 6a2903d3e..273bd56d4 100644 --- a/.github/workflows/shared-testing-macos.yml +++ b/.github/workflows/shared-testing-macos.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: macOS Tests" on: workflow_call: @@ -65,9 +66,7 @@ jobs: - name: Set macOS Check Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} @@ -125,9 +124,7 @@ jobs: -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} - name: Pack Tool E2E - # noinspection UndefinedAction uses: ./.github/actions/packtool-e2e - # noinspection UndefinedParamsPresent with: project: examples/InfiniFrameExample.SingleFileExe/InfiniFrameExample.SingleFileExe.csproj rid: ${{ matrix.rid }} @@ -144,9 +141,7 @@ jobs: if: always() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check-finalize - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} diff --git a/.github/workflows/shared-testing-python.yml b/.github/workflows/shared-testing-python.yml index 8dcc64b4b..5af6b9803 100644 --- a/.github/workflows/shared-testing-python.yml +++ b/.github/workflows/shared-testing-python.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Python Tests" permissions: contents: read diff --git a/.github/workflows/shared-testing-windows-playwright.yml b/.github/workflows/shared-testing-windows-playwright.yml index 1caf8b1ad..8f205f680 100644 --- a/.github/workflows/shared-testing-windows-playwright.yml +++ b/.github/workflows/shared-testing-windows-playwright.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Windows Playwright Tests" on: @@ -42,9 +43,7 @@ jobs: - name: Set Playwright Check Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} @@ -102,9 +101,7 @@ jobs: - name: Set Playwright Check Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} @@ -223,9 +220,7 @@ jobs: if: always() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check-finalize - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} @@ -253,9 +248,7 @@ jobs: - name: Set Playwright Check Final Status env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check-finalize - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} diff --git a/.github/workflows/shared-testing-windows-trim-aot.yml b/.github/workflows/shared-testing-windows-trim-aot.yml index b4c8db820..5f6823dfd 100644 --- a/.github/workflows/shared-testing-windows-trim-aot.yml +++ b/.github/workflows/shared-testing-windows-trim-aot.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Windows Trim/AOT Validation" on: @@ -47,9 +48,7 @@ jobs: - name: Set Trim/AOT Check Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction, UndefinedParamsPresent uses: ./.github/actions/sync-check - # noinspection UndefinedAction, UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ env.TARGET_SHA }} @@ -60,9 +59,7 @@ jobs: allow-status-422: 'true' - name: Setup Native dependencies - # noinspection UndefinedAction uses: ./.github/actions/setup-dependencies-native - # noinspection UndefinedParamsPresent with: brew-cache-key: ${{ runner.os }}-x64-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-windows-trim-aot.yml') }} brew-restore-key: ${{ runner.os }}-x64-brew-native- @@ -154,9 +151,7 @@ jobs: if: always() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction, UndefinedParamsPresent uses: ./.github/actions/sync-check-finalize - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ env.TARGET_SHA }} diff --git a/.github/workflows/shared-testing-windows.yml b/.github/workflows/shared-testing-windows.yml index fc3e5aeb1..93a4035c3 100644 --- a/.github/workflows/shared-testing-windows.yml +++ b/.github/workflows/shared-testing-windows.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Windows Tests" on: workflow_call: @@ -62,9 +63,7 @@ jobs: - name: Set Windows Check Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction uses: ./.github/actions/sync-check - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} @@ -221,9 +220,7 @@ jobs: # artifacts/testresults/** - name: Pack Tool E2E - # noinspection UndefinedAction uses: ./.github/actions/packtool-e2e - # noinspection UndefinedParamsPresent with: project: examples/InfiniFrameExample.SingleFileExe/InfiniFrameExample.SingleFileExe.csproj rid: ${{ matrix.rid }} @@ -240,9 +237,7 @@ jobs: if: always() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # noinspection UndefinedAction, UndefinedParamsPresent uses: ./.github/actions/sync-check-finalize - # noinspection UndefinedParamsPresent with: repo: ${{ github.repository }} sha: ${{ inputs.target_sha }} diff --git a/.github/workflows/shared-testing.yml b/.github/workflows/shared-testing.yml index bf83bd70b..b79cd493c 100644 --- a/.github/workflows/shared-testing.yml +++ b/.github/workflows/shared-testing.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: "Shared: Platform Tests" permissions: contents: read @@ -76,7 +77,6 @@ jobs: echo "sha=$SHA" >> $GITHUB_OUTPUT - # noinspection UndefinedAction, UndefinedParamsPresent docs-validation: name: Validate Docs if: ${{ inputs.run_docs == true }} @@ -87,7 +87,6 @@ jobs: target_sha: ${{ needs.prepare.outputs.sha }} secrets: inherit - # noinspection UndefinedAction, UndefinedParamsPresent js-validation: name: Validate JS needs: [ prepare ] @@ -96,7 +95,6 @@ jobs: checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} - # noinspection UndefinedAction, UndefinedParamsPresent native-build: name: Build Native Artifacts needs: [ prepare ] @@ -107,7 +105,6 @@ jobs: target_sha: ${{ needs.prepare.outputs.sha }} enable_test_exports: ${{ inputs.enable_test_exports }} - # noinspection UndefinedAction, UndefinedParamsPresent dotnetpack-validation: name: Validate Dotnet Pack needs: [ prepare, native-build ] @@ -117,7 +114,6 @@ jobs: target_sha: ${{ needs.prepare.outputs.sha }} enable_test_exports: ${{ inputs.enable_test_exports }} - # noinspection UndefinedAction, UndefinedParamsPresent linux: name: Linux Tests if: ${{ inputs.run_linux == true }} @@ -131,7 +127,6 @@ jobs: enable_test_exports: ${{ inputs.enable_test_exports }} secrets: inherit - # noinspection UndefinedAction, UndefinedParamsPresent macos: name: macOS Tests if: ${{ inputs.run_macos == true }} @@ -145,7 +140,6 @@ jobs: enable_test_exports: ${{ inputs.enable_test_exports }} secrets: inherit - # noinspection UndefinedAction, UndefinedParamsPresent windows: name: Windows Tests if: ${{ inputs.run_windows == true }} @@ -159,7 +153,6 @@ jobs: enable_test_exports: ${{ inputs.enable_test_exports }} secrets: inherit - # noinspection UndefinedAction, UndefinedParamsPresent windows-playwright: name: Windows Playwright Tests if: ${{ inputs.run_windows_playwright == true }} @@ -173,7 +166,6 @@ jobs: enable_test_exports: ${{ inputs.enable_test_exports }} secrets: inherit - # noinspection UndefinedAction, UndefinedParamsPresent windows-trim-aot: name: Validate Trim/AOT if: ${{ inputs.run_trim_aot == true }} From 0f224292903b31de7ed906a7d86f3446d6e82a18 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:15:41 +0200 Subject: [PATCH 43/86] Update CodeQL workflow to add architecture matrix and improve platform-specific configurations --- .github/workflows/ci-codeql.yml | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml index 4f027d9bc..a7dfd6d2d 100644 --- a/.github/workflows/ci-codeql.yml +++ b/.github/workflows/ci-codeql.yml @@ -221,11 +221,11 @@ jobs: category: "/language:csharp" analyze-cpp: - name: Analyze C/C++ (${{ matrix.os }}) + name: Analyze C/C++ (${{ matrix.os }} / ${{ matrix.arch }}) needs: changes runs-on: ${{ matrix.os }} timeout-minutes: 90 - + if: > ( github.event_name == 'workflow_dispatch' && @@ -233,15 +233,20 @@ jobs: ) || ( needs.changes.outputs.cpp == 'true' ) - + strategy: fail-fast: false matrix: - os: - - ubuntu-latest - - windows-latest - # - macos-latest # support is currently experimental and requires additional setup - + include: + - os: ubuntu-latest + arch: x64 + + - os: windows-latest + arch: x64 + + - os: macos-latest + arch: arm64 + permissions: contents: read security-events: write @@ -249,7 +254,7 @@ jobs: packages: read pull-requests: write checks: write - + steps: - name: Checkout uses: actions/checkout@v6 @@ -262,8 +267,8 @@ jobs: - name: Setup Native Dependencies uses: ./.github/actions/setup-dependencies-native with: - brew-cache-key: ${{ runner.os }}-brew-codeql-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-macos.yml') }} - brew-restore-key: ${{ runner.os }}-brew-codeql- + brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-codeql-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/ci-codeql.yml') }} + brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-codeql- - name: Initialize CodeQL uses: github/codeql-action/init@v4 @@ -284,12 +289,12 @@ jobs: --configuration Release ` --no-restore ` -p:SolutionDir="${{ github.workspace }}/" ` - -p:Platform=x64 + -p:CMakePlatform=${{ matrix.arch }} - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 with: - category: "/language:c-cpp" + category: "/language:c-cpp/${{ matrix.os }}-${{ matrix.arch }}" analyze-javascript-typescript: name: Analyze JavaScript / TypeScript From 60b9e13c786c83d0dde0506de3e9b46133a9d7fe Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:18:48 +0200 Subject: [PATCH 44/86] Update CodeQL paths to reflect `NativeBridge` folder structure changes --- .github/codeql-config.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/codeql-config.yml b/.github/codeql-config.yml index 45ee89219..3bb3c721b 100644 --- a/.github/codeql-config.yml +++ b/.github/codeql-config.yml @@ -10,16 +10,16 @@ paths: # Exclude third-party and generated content from CodeQL alerting. paths-ignore: - - "src/InfiniFrame.Native/artifacts/**" - - "src/InfiniFrame.Native/build/**" - - "src/InfiniFrame.Native/packages/**" - - "src/InfiniFrame.Native/cmake-build-debug/**" - - "src/InfiniFrame.Native/cmake-build-debug-linux/**" - - "src/InfiniFrame.Native/cmake-build-debug-windows/**" - - "src/InfiniFrame.Native/cmake-build-release/**" - - "src/InfiniFrame.Native/cmake-build-release-linux/**" - - "src/InfiniFrame.Native/cmake-build-release-windows/**" - - "src/InfiniFrame.Native/Dependencies/**" + - "src/InfiniFrame.NativeBridge/artifacts/**" + - "src/InfiniFrame.NativeBridge/build/**" + - "src/InfiniFrame.NativeBridge/Native/cmake-build-debug/**" + - "src/InfiniFrame.NativeBridge/Native/cmake-build-debug-linux/**" + - "src/InfiniFrame.NativeBridge/Native/cmake-build-debug-windows/**" + - "src/InfiniFrame.NativeBridge/Native/cmake-build-release/**" + - "src/InfiniFrame.NativeBridge/Native/cmake-build-release-linux/**" + - "src/InfiniFrame.NativeBridge/Native/cmake-build-release-windows/**" + - "src/InfiniFrame.NativeBridge/Native/Dependencies/**" + - "src/InfiniFrame.NativeBridge/Native/packages/**" - "tests/**" - "**/node_modules/**" - "**/dist/**" From d62982b0de913b0151669da8f0d4c98e770f0d65 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:30:57 +0200 Subject: [PATCH 45/86] Remove `enable_test_exports` feature flag and update workflows to validate native test exports --- .../workflows/shared-testing-dotnetpack.yml | 69 ++++++++++++++++--- .github/workflows/shared-testing.yml | 1 - 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/.github/workflows/shared-testing-dotnetpack.yml b/.github/workflows/shared-testing-dotnetpack.yml index b379f11b4..fc0b2ba60 100644 --- a/.github/workflows/shared-testing-dotnetpack.yml +++ b/.github/workflows/shared-testing-dotnetpack.yml @@ -13,11 +13,6 @@ on: description: 'Commit SHA used for status/check updates' type: string required: true - enable_test_exports: - description: 'Enable native/managed test exports when validating pack.' - type: boolean - required: false - default: false permissions: contents: read @@ -43,6 +38,9 @@ jobs: with: cache-dotnet: false + - name: Setup dependencies + uses: ./.github/actions/setup-dependencies-native + - name: Set Dotnet Pack Check Pending env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -70,16 +68,16 @@ jobs: --configuration Release \ --no-restore \ /p:SolutionDir=${{ github.workspace }}/ \ - /p:InfiniFrameSkipNativeBuild=true \ - /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} + /p:InfiniFrameSkipNativeBuild=false \ + /p:InfiniFrameEnableTestExports=false - name: Pack run: | dotnet pack InfiniFrame.GitHubActions.Release.slnf \ --configuration Release \ --no-build \ - /p:InfiniFrameSkipNativeBuild=true \ - /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} \ + /p:InfiniFrameSkipNativeBuild=false \ + /p:InfiniFrameEnableTestExports=false \ -o ./release - name: Verify NativeBridge Package Natives @@ -118,6 +116,59 @@ jobs: echo "❌ $MISSING native file(s) missing in NativeBridge package" exit 1 fi + + - name: Verify NativeBridge Test Exports + shell: bash + run: | + set -euo pipefail + + PACKAGE=$(ls ./release/InfiniLore.InfiniFrame.NativeBridge.*.nupkg 2>/dev/null | grep -v '\.symbols\.nupkg$' | head -n 1 || true) + + if [ -z "$PACKAGE" ]; then + echo "❌ No InfiniFrame.NativeBridge package found in ./release" + exit 1 + fi + + echo "Inspecting package: $PACKAGE" + + DLL_PATH="runtimes/win-x64/native/InfiniFrame.Native.dll" + + if ! unzip -l "$PACKAGE" | grep -q "$DLL_PATH"; then + echo "❌ Missing $DLL_PATH in package" + exit 1 + fi + + mkdir -p ./tmp/native-check + + unzip -p "$PACKAGE" "$DLL_PATH" > ./tmp/native-check/InfiniFrame.Native.dll + + sudo apt-get update + sudo apt-get install -y binutils-mingw-w64-x86-64 + + DLL=./tmp/native-check/InfiniFrame.Native.dll + + REQUIRED_EXPORTS=( + "InfiniFrameNativeTests_NativeParametersReturnAsIs" + "InfiniFrameNativeTests_FreeInitParams" + ) + + MISSING=0 + + for export_name in "${REQUIRED_EXPORTS[@]}"; do + if x86_64-w64-mingw32-nm -g --defined-only "$DLL" | grep -q "$export_name"; then + echo "✅ Found export: $export_name" + else + echo "❌ Missing export: $export_name" + MISSING=$((MISSING+1)) + fi + done + + if [ "$MISSING" -gt 0 ]; then + echo "❌ $MISSING required test export(s) missing from InfiniFrame.Native.dll" + exit 1 + fi + + echo "✅ All required test exports found" - name: Complete Dotnet Pack Check if: always() diff --git a/.github/workflows/shared-testing.yml b/.github/workflows/shared-testing.yml index b79cd493c..3cc819fdd 100644 --- a/.github/workflows/shared-testing.yml +++ b/.github/workflows/shared-testing.yml @@ -112,7 +112,6 @@ jobs: with: checkout_ref: ${{ inputs.checkout_ref }} target_sha: ${{ needs.prepare.outputs.sha }} - enable_test_exports: ${{ inputs.enable_test_exports }} linux: name: Linux Tests From 0fd8f525060844dbdcece1f6533764020207010c Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:46:19 +0200 Subject: [PATCH 46/86] Update workflow to validate absence of forbidden NativeBridge test exports --- .../workflows/shared-testing-dotnetpack.yml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/shared-testing-dotnetpack.yml b/.github/workflows/shared-testing-dotnetpack.yml index fc0b2ba60..7a11048c2 100644 --- a/.github/workflows/shared-testing-dotnetpack.yml +++ b/.github/workflows/shared-testing-dotnetpack.yml @@ -117,7 +117,7 @@ jobs: exit 1 fi - - name: Verify NativeBridge Test Exports + - name: Verify Lack of NativeBridge Test Exports shell: bash run: | set -euo pipefail @@ -147,28 +147,28 @@ jobs: DLL=./tmp/native-check/InfiniFrame.Native.dll - REQUIRED_EXPORTS=( + FORBIDDEN_EXPORTS=( "InfiniFrameNativeTests_NativeParametersReturnAsIs" "InfiniFrameNativeTests_FreeInitParams" ) - MISSING=0 + FOUND=0 - for export_name in "${REQUIRED_EXPORTS[@]}"; do - if x86_64-w64-mingw32-nm -g --defined-only "$DLL" | grep -q "$export_name"; then - echo "✅ Found export: $export_name" + for export_name in "${FORBIDDEN_EXPORTS[@]}"; do + if x86_64-w64-mingw32-nm -g --defined-only "$DLL" | awk '{print $3}' | grep -Fxq "$export_name"; then + echo "❌ Forbidden test export found: $export_name" + FOUND=$((FOUND+1)) else - echo "❌ Missing export: $export_name" - MISSING=$((MISSING+1)) + echo "✅ Export not present: $export_name" fi done - if [ "$MISSING" -gt 0 ]; then - echo "❌ $MISSING required test export(s) missing from InfiniFrame.Native.dll" + if [ "$FOUND" -gt 0 ]; then + echo "❌ $FOUND forbidden test export(s) found in InfiniFrame.Native.dll" exit 1 fi - echo "✅ All required test exports found" + echo "✅ No forbidden test exports found" - name: Complete Dotnet Pack Check if: always() From 7f31b6dd16d9a8710305ec621ad21c1f82ba5e97 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:51:57 +0200 Subject: [PATCH 47/86] Potential fix for pull request finding 'CodeQL / Poorly documented large function' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../Windows/WebView/WebView2Attach.Win32.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp index 07e0b90f2..2ca93d097 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp @@ -27,14 +27,28 @@ void InfiniFrameWindow::Show(const bool isAlreadyShown) { } } +// Initializes and attaches the WebView2 instance to this window. +// +// High-level flow: +// 1) Bail out if the window is already closing/closed, or if initialization has already started/completed. +// 2) Resolve an optional runtime path under lock (if configured by the host). +// 3) Build browser startup arguments from feature flags and host-provided parameters. +// 4) Continue with WebView2 environment/controller creation and event wiring (below). +// +// Notes: +// - This function is intentionally stateful and order-sensitive; do not reorder guard checks. +// - The `_isWebView2Initializing` flag prevents duplicate initialization attempts. void InfiniFrameWindow::AttachWebView() { + // Guard: no attachment work should run after close has been requested. if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) return; + // Guard: avoid concurrent or repeated initialization. if (m_impl->_isWebView2Initializing || m_impl->_isInitialized) return; m_impl->_isWebView2Initializing = true; + // Snapshot runtime path under lock so subsequent async setup uses a stable value. std::wstring configuredRuntimePath; { std::lock_guard lock(webview2RuntimePathMutex); @@ -42,6 +56,7 @@ void InfiniFrameWindow::AttachWebView() { } PCWSTR runtimePath = configuredRuntimePath.empty() ? nullptr : configuredRuntimePath.c_str(); + // Compose WebView2 command-line switches from current window/browser options. std::wstring startupString; if (!m_impl->_userAgent.empty()) startupString += L"--user-agent=\"" + m_impl->_userAgent + L"\" "; From e5f9b758a098a25b3b348542236b6c0df4a877ca Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:52:27 +0200 Subject: [PATCH 48/86] Potential fix for pull request finding 'CodeQL / Poorly documented large function' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../Platform/Windows/Core/WindowLifecycle.Win32.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp index eccbb3ccb..c225508e5 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp @@ -75,8 +75,17 @@ void InfiniFrameWindow::Register(const HINSTANCE hInstance) { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); } +// Initializes native window lifecycle state from host-provided startup parameters. +// Flow: +// 1) Allocate implementation storage. +// 2) Validate ABI compatibility of InfiniFrameInitParams via StructSize. +// 3) Configure window identity/notifications and startup payload values. +// 4) Continue with remaining platform/window initialization in this constructor. InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { + // Backing implementation object must exist before any field assignment. m_impl = std::make_unique(); + + // Fail fast if caller and native side disagree on struct layout/version. if (initParams->StructSize != sizeof(InfiniFrameInitParams)) { auto msg = std::format( L"Initial parameters passed are {} bytes, but expected {} bytes.", initParams->StructSize, @@ -86,6 +95,7 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { exit(0); } + // Initialize window title and optional toast notification identity. if (initParams->Title != nullptr) { m_impl->_windowTitle = ToUTF16String(initParams->Title); if (initParams->NotificationsEnabled) { @@ -95,9 +105,11 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) { } } + // Capture startup URL (if provided) for initial navigation/bootstrap. if (initParams->StartUrl != nullptr) m_impl->_startUrl = ToUTF16String(initParams->StartUrl); + // Capture startup string payload (if provided) for host-defined boot data. if (initParams->StartString != nullptr) m_impl->_startString = ToUTF16String(initParams->StartString); From f9dbc05f9fa6f96e2efeed00829bcc72f8bbd596 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 12:52:40 +0200 Subject: [PATCH 49/86] Potential fix for pull request finding 'CodeQL / Poorly documented large function' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../Platform/Windows/Core/WindowProc.Win32.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp index 0e10e21e5..cdda533e8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp @@ -1,21 +1,33 @@ #include "../DarkMode.h" #include "../Window.Win32.Context.h" +// Central Win32 message dispatcher for an InfiniFrame top-level window. +// This procedure coordinates native lifecycle events with managed/window context state: +// - stores and retrieves the InfiniFrameWindow instance +// - reacts to theme and color-scheme changes (dark/light mode) +// - applies per-monitor DPI resize recommendations +// - forwards focus and close events to the owning instance +// - paints the window background according to current theme LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { switch (uMsg) { case WM_NCCREATE: { + // Capture the instance pointer at non-client creation so later messages can + // resolve window state via GWLP_USERDATA. const auto* createParams = reinterpret_cast(lParam); auto* instance = reinterpret_cast(createParams->lpCreateParams); SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast(instance)); return TRUE; } case WM_CREATE: { + // Initialize dark mode support once the window is created. EnableDarkMode(hwnd, true); if (IsDarkModeEnabled()) RefreshNonClientArea(hwnd); break; } case WM_DPICHANGED: { + // Use the system-provided suggested rectangle to keep the window properly sized + // and positioned when moving between monitors with different DPI. RECT* newWindowRect = reinterpret_cast(lParam); SetWindowPos( @@ -26,18 +38,21 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara return 0; } case WM_SETTINGCHANGE: { + // Forward color-scheme changes to the same theme-refresh path used by WM_THEMECHANGED. if (IsColorSchemeChange(lParam)) SendMessageW(hwnd, WM_THEMECHANGED, 0, 0); break; } case WM_THEMECHANGED: { + // Reapply dark mode and redraw client/non-client regions after a theme transition. EnableDarkMode(hwnd, IsDarkModeEnabled()); RefreshNonClientArea(hwnd); InvalidateRect(hwnd, nullptr, TRUE); break; } case WM_PAINT: { + // Paint only the invalidated region with the active theme background brush. PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); @@ -51,6 +66,7 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara break; } case WM_ACTIVATE: { + // Keep WebView/focus state synchronized with native activation transitions. InfiniFrameWindow* instance = LookupWindowInstance(hwnd); if (instance) { if (LOWORD(wParam) == WA_INACTIVE) { @@ -65,6 +81,8 @@ LRESULT CALLBACK WindowProc(const HWND hwnd, const UINT uMsg, const WPARAM wPara break; } case WM_CLOSE: { + // Give the instance a chance to cancel close. If close proceeds, clear owner + // relationship before destruction to avoid shutdown-order and ownership edge cases. InfiniFrameWindow* instance = LookupWindowInstance(hwnd); if (instance) { TraceTeardown(L"WM_CLOSE hwnd=%p instance=%p", hwnd, instance); From 37223547d967ad775411d814953dcbfe97703ef8 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 13:25:05 +0200 Subject: [PATCH 50/86] Add `Import.targets` for native dependencies and improve project references - Introduced `Import.targets` to handle native dependencies for various platforms. - Updated project references to include `InfiniFrame.NativeBridge`. - Transitioned from `None` to `Content` for processing and linking native files. - Minor formatting updates and cleanup across multiple files. --- examples/Directory.Build.props | 4 +- .../Components/App.razor | 1 - .../Components/Pages/PageNotFound.razor | 4 +- .../InfiniFrameExample.BlazorWebView.csproj | 17 ++- .../README.md | 3 +- .../wwwroot/sample-data/weather.json | 50 ++++----- src/InfiniFrame.NativeBridge/Import.targets | 102 ++++++++++++++++++ .../InfiniFrame.NativeBridge.csproj | 85 +++++++++------ .../InfiniFrame.Shared.csproj | 4 +- 9 files changed, 205 insertions(+), 65 deletions(-) create mode 100644 src/InfiniFrame.NativeBridge/Import.targets diff --git a/examples/Directory.Build.props b/examples/Directory.Build.props index 0e955e684..18a8d8e74 100644 --- a/examples/Directory.Build.props +++ b/examples/Directory.Build.props @@ -2,10 +2,10 @@ Exe - + net10.0 14.0 - + enable enable false diff --git a/examples/InfiniFrameExample.BlazorWebView/Components/App.razor b/examples/InfiniFrameExample.BlazorWebView/Components/App.razor index 1ad1dd6ec..7978ff4ce 100644 --- a/examples/InfiniFrameExample.BlazorWebView/Components/App.razor +++ b/examples/InfiniFrameExample.BlazorWebView/Components/App.razor @@ -1,6 +1,5 @@ @using InfiniFrameExample.BlazorWebView.Components.Layouts @using InfiniFrameExample.BlazorWebView.Components.Pages - diff --git a/examples/InfiniFrameExample.BlazorWebView/Components/Pages/PageNotFound.razor b/examples/InfiniFrameExample.BlazorWebView/Components/Pages/PageNotFound.razor index 2d1913c9b..20b1013c5 100644 --- a/examples/InfiniFrameExample.BlazorWebView/Components/Pages/PageNotFound.razor +++ b/examples/InfiniFrameExample.BlazorWebView/Components/Pages/PageNotFound.razor @@ -1,12 +1,12 @@ @* ------------------------------------------------------------------------------------------------------------------ *@ @* Imports @* ------------------------------------------------------------------------------------------------------------------ *@ -@using InfiniFrameExample.BlazorWebView.Components.Layouts @* ------------------------------------------------------------------------------------------------------------------ *@ @* Descriptors @* ------------------------------------------------------------------------------------------------------------------ *@ @page "/PageNotFound" +@using InfiniFrameExample.BlazorWebView.Components.Layouts @layout MainLayout @* ------------------------------------------------------------------------------------------------------------------ *@ @@ -19,6 +19,6 @@ @* ------------------------------------------------------------------------------------------------------------------ *@ @code { - + } diff --git a/examples/InfiniFrameExample.BlazorWebView/InfiniFrameExample.BlazorWebView.csproj b/examples/InfiniFrameExample.BlazorWebView/InfiniFrameExample.BlazorWebView.csproj index 96eda0933..13dab3083 100644 --- a/examples/InfiniFrameExample.BlazorWebView/InfiniFrameExample.BlazorWebView.csproj +++ b/examples/InfiniFrameExample.BlazorWebView/InfiniFrameExample.BlazorWebView.csproj @@ -5,9 +5,13 @@ - - - + + + + + + true + @@ -16,4 +20,11 @@ + + + + + + + diff --git a/examples/InfiniFrameExample.BlazorWebView/README.md b/examples/InfiniFrameExample.BlazorWebView/README.md index 92baad31b..e7b4277e6 100644 --- a/examples/InfiniFrameExample.BlazorWebView/README.md +++ b/examples/InfiniFrameExample.BlazorWebView/README.md @@ -1,6 +1,7 @@ # Example: BlazorWebView -Demonstrates the minimal setup for hosting a Blazor application inside a native InfiniFrame window using `InfiniLore.InfiniFrame.BlazorWebView` +Demonstrates the minimal setup for hosting a Blazor application inside a native InfiniFrame window using +`InfiniLore.InfiniFrame.BlazorWebView` ## What it shows diff --git a/examples/InfiniFrameExample.BlazorWebView/wwwroot/sample-data/weather.json b/examples/InfiniFrameExample.BlazorWebView/wwwroot/sample-data/weather.json index 06463c02f..bed52c923 100644 --- a/examples/InfiniFrameExample.BlazorWebView/wwwroot/sample-data/weather.json +++ b/examples/InfiniFrameExample.BlazorWebView/wwwroot/sample-data/weather.json @@ -1,27 +1,27 @@ [ - { - "date": "2018-05-06", - "temperatureC": 1, - "summary": "Freezing" - }, - { - "date": "2018-05-07", - "temperatureC": 14, - "summary": "Bracing" - }, - { - "date": "2018-05-08", - "temperatureC": -13, - "summary": "Freezing" - }, - { - "date": "2018-05-09", - "temperatureC": -16, - "summary": "Balmy" - }, - { - "date": "2018-05-10", - "temperatureC": -2, - "summary": "Chilly" - } + { + "date": "2018-05-06", + "temperatureC": 1, + "summary": "Freezing" + }, + { + "date": "2018-05-07", + "temperatureC": 14, + "summary": "Bracing" + }, + { + "date": "2018-05-08", + "temperatureC": -13, + "summary": "Freezing" + }, + { + "date": "2018-05-09", + "temperatureC": -16, + "summary": "Balmy" + }, + { + "date": "2018-05-10", + "temperatureC": -2, + "summary": "Chilly" + } ] diff --git a/src/InfiniFrame.NativeBridge/Import.targets b/src/InfiniFrame.NativeBridge/Import.targets new file mode 100644 index 000000000..2c5777db5 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Import.targets @@ -0,0 +1,102 @@ + + + <_InfiniFrameNativeOutputRoot>$(MSBuildThisFileDirectory)..\artifacts\native + + <_WinX64>$(_InfiniFrameNativeOutputRoot)\windows\x64\$(Configuration) + <_WinArm64>$(_InfiniFrameNativeOutputRoot)\windows\arm64\$(Configuration) + + <_LinuxX64>$(_InfiniFrameNativeOutputRoot)\linux\x64\$(Configuration) + <_LinuxArm64>$(_InfiniFrameNativeOutputRoot)\linux\arm64\$(Configuration) + + <_OsxX64>$(_InfiniFrameNativeOutputRoot)\osx\x64\$(Configuration) + <_OsxArm64>$(_InfiniFrameNativeOutputRoot)\osx\arm64\$(Configuration) + + + + + + + Always + Always + InfiniFrame.Native.dll + InfiniFrame.Native.dll + + + + Always + Always + WebView2Loader.dll + WebView2Loader.dll + + + + + + + + + Always + Always + InfiniFrame.Native.dll + InfiniFrame.Native.dll + + + + Always + Always + WebView2Loader.dll + WebView2Loader.dll + + + + + + + + + Always + Always + InfiniFrame.Native.so + InfiniFrame.Native.so + + + + + + + + + Always + Always + InfiniFrame.Native.so + InfiniFrame.Native.so + + + + + + + + + Always + Always + InfiniFrame.Native.dylib + InfiniFrame.Native.dylib + + + + + + + + + Always + Always + InfiniFrame.Native.dylib + InfiniFrame.Native.dylib + + + + \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index 0a18ce86f..7f79a713e 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -3,6 +3,7 @@ InfiniLore.InfiniFrame.NativeBridge Library + true true @@ -58,72 +59,96 @@ - + PackagePath="runtimes/win-x64/native/" + Link="InfiniFrame.Native.dll" + Visible="false" + /> - + PackagePath="runtimes/win-x64/native/" + Link="WebView2Loader.dll" + Visible="false" + /> - + PackagePath="runtimes/win-arm64/native/" + Link="InfiniFrame.Native.dll" + Visible="false" + /> - + PackagePath="runtimes/win-arm64/native/" + Link="WebView2Loader.dll" + Visible="false" + /> - + PackagePath="runtimes/linux-x64/native/" + Link="InfiniFrame.Native.so" + Visible="false" + /> - + - + PackagePath="runtimes/osx-x64/native/" + Link="InfiniFrame.Native.dylib" + Visible="false" + /> - + @@ -152,28 +177,28 @@ Text="✅ Found InfiniFrame.Native.dll in $(WindowsX64)" Importance="High"/> @@ -182,28 +207,28 @@ Text="✅ Found InfiniFrame.Native.dll in $(WindowsArm64)" Importance="High"/> diff --git a/src/InfiniFrame.Shared/InfiniFrame.Shared.csproj b/src/InfiniFrame.Shared/InfiniFrame.Shared.csproj index ad0d0eddc..a485673a2 100644 --- a/src/InfiniFrame.Shared/InfiniFrame.Shared.csproj +++ b/src/InfiniFrame.Shared/InfiniFrame.Shared.csproj @@ -15,7 +15,9 @@ - + + true + From b3a6f59d33fffde49e7b9691d905cf80e38e0d39 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 13:39:42 +0200 Subject: [PATCH 51/86] Remove redundant native dependency handling and upgrade TUnit to v1.45.0. --- Directory.Packages.props | 8 +- InfiniFrame.slnx | 1 - .../InfiniFrameExample.BlazorWebView.csproj | 11 -- src/InfiniFrame.NativeBridge/Import.targets | 102 ------------------ .../InfiniFrame.NativeBridge.csproj | 48 ++++----- tests/Directory.Build.props | 28 +---- tests/Directory.Build.targets | 21 ---- 7 files changed, 29 insertions(+), 190 deletions(-) delete mode 100644 src/InfiniFrame.NativeBridge/Import.targets delete mode 100644 tests/Directory.Build.targets diff --git a/Directory.Packages.props b/Directory.Packages.props index 08a46edde..2307816fb 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -33,9 +33,9 @@ - - - - + + + + \ No newline at end of file diff --git a/InfiniFrame.slnx b/InfiniFrame.slnx index 85f479354..1d28fd2f5 100644 --- a/InfiniFrame.slnx +++ b/InfiniFrame.slnx @@ -177,7 +177,6 @@ - diff --git a/examples/InfiniFrameExample.BlazorWebView/InfiniFrameExample.BlazorWebView.csproj b/examples/InfiniFrameExample.BlazorWebView/InfiniFrameExample.BlazorWebView.csproj index 13dab3083..32916d77a 100644 --- a/examples/InfiniFrameExample.BlazorWebView/InfiniFrameExample.BlazorWebView.csproj +++ b/examples/InfiniFrameExample.BlazorWebView/InfiniFrameExample.BlazorWebView.csproj @@ -8,10 +8,6 @@ - - - true - @@ -20,11 +16,4 @@ - - - - - - - diff --git a/src/InfiniFrame.NativeBridge/Import.targets b/src/InfiniFrame.NativeBridge/Import.targets deleted file mode 100644 index 2c5777db5..000000000 --- a/src/InfiniFrame.NativeBridge/Import.targets +++ /dev/null @@ -1,102 +0,0 @@ - - - <_InfiniFrameNativeOutputRoot>$(MSBuildThisFileDirectory)..\artifacts\native - - <_WinX64>$(_InfiniFrameNativeOutputRoot)\windows\x64\$(Configuration) - <_WinArm64>$(_InfiniFrameNativeOutputRoot)\windows\arm64\$(Configuration) - - <_LinuxX64>$(_InfiniFrameNativeOutputRoot)\linux\x64\$(Configuration) - <_LinuxArm64>$(_InfiniFrameNativeOutputRoot)\linux\arm64\$(Configuration) - - <_OsxX64>$(_InfiniFrameNativeOutputRoot)\osx\x64\$(Configuration) - <_OsxArm64>$(_InfiniFrameNativeOutputRoot)\osx\arm64\$(Configuration) - - - - - - - Always - Always - InfiniFrame.Native.dll - InfiniFrame.Native.dll - - - - Always - Always - WebView2Loader.dll - WebView2Loader.dll - - - - - - - - - Always - Always - InfiniFrame.Native.dll - InfiniFrame.Native.dll - - - - Always - Always - WebView2Loader.dll - WebView2Loader.dll - - - - - - - - - Always - Always - InfiniFrame.Native.so - InfiniFrame.Native.so - - - - - - - - - Always - Always - InfiniFrame.Native.so - InfiniFrame.Native.so - - - - - - - - - Always - Always - InfiniFrame.Native.dylib - InfiniFrame.Native.dylib - - - - - - - - - Always - Always - InfiniFrame.Native.dylib - InfiniFrame.Native.dylib - - - - \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index 7f79a713e..9a892cc47 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -60,10 +60,10 @@ @@ -71,10 +71,10 @@ @@ -83,10 +83,10 @@ @@ -94,10 +94,10 @@ @@ -106,10 +106,10 @@ @@ -130,10 +130,10 @@ diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index a0a3273a0..5b0752b19 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -3,39 +3,13 @@ net8.0;net9.0;net10.0 14.0 - + enable enable true false - false $(MSBuildProjectDirectory)\bin\$(Configuration)\$(TargetFramework)\ - $(Platform) - x64 - $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows))) - $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux))) - $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX))) - - x64 - arm64 - x64 - - build/$(CMakeArch)/$(Configuration) - windows - linux - osx - - $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\')) - $(SolutionDir) - $(RepoRootDir) - $(ResolvedSolutionDir)src/InfiniFrame.NativeBridge/artifacts/native - $(ResolvedSolutionDir)artifacts/native - $(NativeBridgeArtifactsRoot) - $(LegacyNativeArtifactsRoot) - $(NativeArtifactsRoot)/$(CMakeOSDir)/$(CMakeArch)/$(Configuration) - - $(DefineConstants);WINDOWS diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets deleted file mode 100644 index 3b2361f18..000000000 --- a/tests/Directory.Build.targets +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - From f25f08c1ac3ce6291908d6c3562c26ed4e811cc3 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 14:14:50 +0200 Subject: [PATCH 52/86] Simplify `GeneratePackageOnBuild` condition to default to true. --- src/Directory.Build.props | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 61a0873c2..e8c3d3eaf 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -32,8 +32,7 @@ true true - false - + true 0.13.1 InfiniFrame, TryPhotino From a07e97e64a1a207ef88665534f6e04cacd343ada Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 14:14:56 +0200 Subject: [PATCH 53/86] Add `current-runner-only` option to `download-native-binaries` action and update workflows - Introduced `current-runner-only` input to enable selective artifact downloads by runner platform. - Updated workflows to use the new option for optimized artifact retrieval. - Enhanced `resolve-runner` logic to determine OS/architecture dynamically. --- .../download-native-binaries/action.yml | 112 ++++++++++++++++-- .github/workflows/shared-release-publish.yml | 1 + .../workflows/shared-testing-dotnetpack.yml | 1 + .github/workflows/shared-testing-linux.yml | 1 + .github/workflows/shared-testing-macos.yml | 1 + .../shared-testing-windows-playwright.yml | 1 + .../shared-testing-windows-trim-aot.yml | 1 + .github/workflows/shared-testing-windows.yml | 1 + 8 files changed, 106 insertions(+), 13 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index e6935f117..67301cddc 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -6,36 +6,110 @@ inputs: description: Artifact naming mode required: true default: testing + target-root: description: Root path where normalized native artifacts should be written required: false default: "" + current-runner-only: + description: Only download artifacts matching the current OS/arch + required: false + default: "false" + runs: using: composite steps: - - name: Resolve Native Artifact Settings - id: resolve-native-artifact-settings + + - name: Resolve Runner Platform + id: resolve-runner shell: bash run: | set -euo pipefail - artifact_type="${{ inputs.artifact-type }}" - input_root="${{ inputs.target-root }}" + os="$RUNNER_OS" + arch="$RUNNER_ARCH" - case "$artifact_type" in - testing) - pattern="native-testing-*" + case "$os" in + Windows) + lib="windows" ;; - release) - pattern="native-*" + Linux) + lib="linux" + ;; + macOS) + lib="osx" ;; *) - echo "Unsupported artifact-type: $artifact_type" + echo "Unsupported OS: $os" exit 1 ;; esac + case "$arch" in + X64|x64) + arch="x64" + ;; + ARM64|arm64) + arch="arm64" + ;; + *) + echo "Unsupported arch: $arch" + exit 1 + ;; + esac + + echo "lib=$lib" >> "$GITHUB_OUTPUT" + echo "arch=$arch" >> "$GITHUB_OUTPUT" + + + - name: Resolve Native Artifact Settings + id: resolve-native-artifact-settings + shell: bash + run: | + set -euo pipefail + + artifact_type="${{ inputs.artifact-type }}" + input_root="${{ inputs.target-root }}" + current_only="${{ inputs.current-runner-only }}" + + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + if [ "$current_only" = "true" ]; then + case "$artifact_type" in + testing) + artifact_name="native-testing-${lib}-${arch}" + ;; + release) + artifact_name="native-${lib}-${arch}" + ;; + *) + echo "Unsupported artifact-type: $artifact_type" + exit 1 + ;; + esac + + echo "mode=name" >> "$GITHUB_OUTPUT" + echo "artifact_name=$artifact_name" >> "$GITHUB_OUTPUT" + else + case "$artifact_type" in + testing) + pattern="native-testing-*" + ;; + release) + pattern="native-*" + ;; + *) + echo "Unsupported artifact-type: $artifact_type" + exit 1 + ;; + esac + + echo "mode=pattern" >> "$GITHUB_OUTPUT" + echo "pattern=$pattern" >> "$GITHUB_OUTPUT" + fi + if [ -n "$input_root" ]; then root="$input_root" elif [ "$artifact_type" = "testing" ]; then @@ -44,14 +118,24 @@ runs: root="artifacts/native" fi - echo "pattern=$pattern" >> "$GITHUB_OUTPUT" echo "root=$root" >> "$GITHUB_OUTPUT" - - name: Download Native Build Artifacts + + - name: Download Native Build Artifacts (current runner only) + if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'name' }} uses: actions/download-artifact@v8 with: + name: ${{ steps.resolve-native-artifact-settings.outputs.artifact_name }} path: artifacts/native + + + - name: Download Native Build Artifacts (all platforms) + if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'pattern' }} + uses: actions/download-artifact@v8 + with: pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }} + path: artifacts/native + - name: Normalize Native Artifacts shell: bash @@ -90,12 +174,14 @@ runs: copy_artifact "native-osx-arm64" "$ROOT/osx/arm64/Release" fi + - name: Verify Native Artifacts shell: bash run: | set -euo pipefail ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" + EXPECTED=( "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" "$ROOT/windows/x64/Release/WebView2Loader.dll" @@ -120,4 +206,4 @@ runs: exit 1 fi - echo "All native artifacts downloaded and verified." + echo "All native artifacts downloaded and verified." \ No newline at end of file diff --git a/.github/workflows/shared-release-publish.yml b/.github/workflows/shared-release-publish.yml index 98869e080..1b9e50f4c 100644 --- a/.github/workflows/shared-release-publish.yml +++ b/.github/workflows/shared-release-publish.yml @@ -60,6 +60,7 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: release + current-runner-only: false # We need to download artifacts from all runners - name: Verify Artifacts run: | diff --git a/.github/workflows/shared-testing-dotnetpack.yml b/.github/workflows/shared-testing-dotnetpack.yml index 7a11048c2..5dae37094 100644 --- a/.github/workflows/shared-testing-dotnetpack.yml +++ b/.github/workflows/shared-testing-dotnetpack.yml @@ -58,6 +58,7 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing + current-runner-only: false # We need to download from all runners - name: Restore run: dotnet restore InfiniFrame.GitHubActions.Release.slnf /p:NoWarn=NU1503 diff --git a/.github/workflows/shared-testing-linux.yml b/.github/workflows/shared-testing-linux.yml index 607e2f7a5..3e3c8f2ba 100644 --- a/.github/workflows/shared-testing-linux.yml +++ b/.github/workflows/shared-testing-linux.yml @@ -75,6 +75,7 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing + current-runner-only: true # Only download artifacts from the current runner - name: Compile GSettings schemas run: sudo glib-compile-schemas /usr/share/glib-2.0/schemas/ diff --git a/.github/workflows/shared-testing-macos.yml b/.github/workflows/shared-testing-macos.yml index 273bd56d4..70eb618eb 100644 --- a/.github/workflows/shared-testing-macos.yml +++ b/.github/workflows/shared-testing-macos.yml @@ -80,6 +80,7 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing + current-runner-only: true # Only download artifacts from the current runner - name: Restore run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 diff --git a/.github/workflows/shared-testing-windows-playwright.yml b/.github/workflows/shared-testing-windows-playwright.yml index 8f205f680..17ce98540 100644 --- a/.github/workflows/shared-testing-windows-playwright.yml +++ b/.github/workflows/shared-testing-windows-playwright.yml @@ -115,6 +115,7 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing + current-runner-only: true - name: NPM Install if: ${{ matrix.project.sourceFolder != '' }} diff --git a/.github/workflows/shared-testing-windows-trim-aot.yml b/.github/workflows/shared-testing-windows-trim-aot.yml index 5f6823dfd..5d85f0e18 100644 --- a/.github/workflows/shared-testing-windows-trim-aot.yml +++ b/.github/workflows/shared-testing-windows-trim-aot.yml @@ -68,6 +68,7 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing + current-runner-only: true # Only download artifacts from the current runner - name: Trim Analyzer Builds run: | diff --git a/.github/workflows/shared-testing-windows.yml b/.github/workflows/shared-testing-windows.yml index 93a4035c3..a28f600f7 100644 --- a/.github/workflows/shared-testing-windows.yml +++ b/.github/workflows/shared-testing-windows.yml @@ -77,6 +77,7 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing + current-runner-only: true # Only download artifacts from the current runner - name: Restore run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 From 31cd3bda5a4f718c4256ffbdf2b98084023e8302 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 14:17:26 +0200 Subject: [PATCH 54/86] Update app icon asset --- assets/icon.png | Bin 123957 -> 17687 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/icon.png b/assets/icon.png index 0d00ee25f133ee12b1b5772ed89f084f26fc8ba7..ad89505d652112d7efd3d0adb1692fa154226363 100644 GIT binary patch literal 17687 zcmXAx2RN4f`^IlOduNkTWRsn;vSsg`P$BcNXY?YnL)m+etn5+9ip(T4Br_wj`Cop2 z$MGJ$%JV$;_}1VMxUMMJJ(!yl%uMYdPpxoIoP zA{9gQYw!)`6PbrH2vQY;fA$CqzQ=V|GIB!@e6p+m&_-ti&Jg55neqb}T`%*kbZ;*T z`HRc>dv_X%U2({+9g<$VW`)kp!Lo?QxmcC6_@V-bg)?ih-{W!nH{XHmuTn- z4CBgwLfgk2PQIMRl2%04ka(mEE!^>+FM0=27FrOc^v$3v~VrR3dyj&%q2(X zM+K>C#$ztvnRlY?@<0ucVF zZL`(YRj+ps5FNBlw2oIoDuJ)C-V=7TB37#pHda@QSaCY6kSLZYzF}RQg?XfDWV-~)&;%}>)7#-Mgp=9gELtpJyk4R@pd)r^*?BE7jp9Jgk z6NHS9>!P;j7#Qw)Jn-?6AR{9qAtw(hD&ioKU2qn&teMi((Fy7AS4q3?PutzyT~twl z&HOT2TeTliL*F6ym+28*#qN-LxjWx^r!D|nSy`D{zzS30HT8>`8B+pkegytz|0~-g zk<_@%%$R$=|15tGrGIa9V_)CcSj#N###qQiR{q|@U`UU>Mbn`l$6ICPzCD-zB}F*$ zY;SJ!4lugRQH*b%o|Dl4)tH@va1Q8e%|QhE6BW@Xz6 zXO(d|Ds`U@j*Ip3s7FdkRyO!XD;`SrkY*THICPJ<8fBAQ_VOjBpywY`tD33Re^mVA zXKc4{JVM+L_{vZHMudCI0!sDAT$| zAAHsu>xhX8&Uk^?J>aZoBc$dJ+MKEhbF`4@OyV(7I{Y(>bsV2PhE%W0PK@AUH=&EM zYZp(yf%p3=`Io?@(G-=6C*dGM=e_e0XJQ{a;)qZKg$fS!K!_rBS40w1QdHV5FMOLA zuOm}9m2NufVBiq3<>%+4rg3Sa>BVJz_E(vE>mTqG z;2SHllXz?8?R_YAS^69o8j9UC_>vyZ;p`V*AnCG2&V@SFhiLU1E|l#T=@kv-cB6U9 z<_8P-LYp3UY3_QIWzn=efNgC55S05MKvxbVNb8L{& zWF&h-d?T3GkAWfZZ=;gUbG^XR>3QD%&w*%RoiYkBj657vxGAbsZP9{4X0JR*-57%0 zQI__m-oFyR*FGcv)aiexVQbfmRy|E@1a)@g;=1yM#;VSkFe)mF5m8f9BS?sk4=yX? z-d~@HTpP_-EgN~d-}k4DkdUxpF@no^XF=vf+ujRV-u+Fnx_XrO^a7LNgl8hh=U`pF zq_lL6DyN`f*0BfHn&EL5xrVOolP3oJ1gzeQk3v3L(up}+c9$8|a0VX#N>)j-Nk^R- zYwPPP{HS;0Q&Ob+G5ECs-jmWO_rk@+WqIdkCyH(uGkU2ZCnu*Qj49wdJsn-?_w%>< zR#sM9uW9alfrrVw##rj|><%tIKKV>D;aUy4M8M4uDZ$8!w>ehSp??3So}gw82zy*+ z{>(O)8<>0N%lC1=)D<9DYW&l*!HJKD*HTTfJ19C&F;hdBJ|;>tvCF<4soQ_u{dcIlr5}uw1x+q zc|~wGm1~|-1J#>3@{uJhEG+cFDT$O&a&VnKF%Q8#wDQ-5-}Z4vlqrcptnRmHh^*197IE!ej*T)xO$mv)1-rO@_N&jjdQc{xPrXS@6wWUw!1h~e&#EwM7BMc@pBR#x{_vcqcECEs-2IS4wHj8Cn~OydWEF?U9{bVqMxlCo z&PEkC90et6{+wqG)|l=D{`Z(Ah$}&s99Ho zk{T{fHr8$!oo!fL?upS8u`)20L4|!g=evC`i6|Mbli#&}yeso_o?9G0Nrxy|^2cu& zUWz~cc6(TMU)e$3j!?XWYt4TD{@lYJn$7+%Ur>#+j!8q6x@{-xTrz3ptKKI+*IqI{ zLRNOC++Bje8PznS_F; zkF);u%UJVPALZG<3vA~k?y_P02;Bq5CSzf=qiY?MXLjw52qU^C=ic=71E@3{B1m0b z9b@hYM_oKlI`m*kxIZq(Gv2?`wFf?T-hIASE5lEOexG>3SV9wn1x>OeQ|`&iJPT9* zy>tIT8DIw zr_(RRAD3r;zrG~G7yj^ky1>gr&UVTp7X$SYGZoECc`++}eu21Mw`;D|H)PAZ*Y@(_ zJYt~GezL;#LNtVEn3PP7vf^G4F3R!->GkWO`}?SF8=uu-W^qbMj@z7^+Gnp4;+RVx z7LK4v$Wj>SOF4&(*9Tfzu~f8Q_`IeUCwuhh(Y{UPNQK$m=tplRoSJ8cCdS7({xIU; zL%|Xuk)@z%f_57+!qFHWzlx+UtdPfzn7>enqLsI^v%8=czwdt{!@JLvV<%pJnQ=PuEv2>N$lGGbI^Ug_uLnh#)`)s!f|cw(^q31e?&; zuHhDF1U--lDtO!zz52b1m4N^WfBm{^xi6v0bK89LM;*TBj0+A6OYJ?IltW#em(yEB z1y8c^k_Ucecjj60Q&T7Ou^rHZhPuoIr+=+RN_ zmiqA% z#Ym3Zw?9Tua`F2eIdd>{jm0S#8d87i?4+a=>~XO)(l0@C9!8V+IB3E$?`^fn7;b+NeX_j8}oD<(;S#BXr%!8-J4W=z=~>)H_+oM`e=8LTmlS z{l@3Nt5-e@PRng@39tw_{QFhP$)$NV!XVpQlCj!$kXF!V|LN#ASKV2pwmj9bNx2G5 z47D1YmOrmCOsS-(#2|>jmjwssECal1639U80GGaRYMD=qaoIJ@2;`Y+U)8X_5c$J)Ubo zk9oE8Pucjy#DhZL)q6o74&a@Jjgr3vW8p80sS;*$#i&0Wj@c$0CN_-^C7{tZ(bmp6 z>A;h{_6`JX=HfR(>5Yi!=vxmT_J1X6h3b(PfbM*jK?Dz-S|&mzMzG)$ASo@)~fb5RH?Py~ak))Y~5;hO7A6 zaP3KnrOur9-U>Xn`AGn9@DF4!N=)WL$&c>AvLVx3=qR{pX_GfDlq@3UVto^GactdosmBjLo( zdPSs(R^xZP_Xg@x4K&`;Y`*ng)_eCDzDia8$;yCc*-Mi-vTWmA1wSpl7cinN?)%T- zi=KhmgyWCeXL>|ooyr!Iai2|`TL1Id`Z4k`{*h6V-(DZPHqK>7AlbSS8wEiSZpS$) z>pF=nLF9EFmA;`NkMn=iPVW2ePLG9XT|oJbeU$0!dPOeaviLy4@H!lYTVhg@%GL#j zG#*11c@sZ!adQ#3ppgJOUE*7zoyl3#d6NeX9OZu+@Q#rY$A4|CLm9ZZzj1a< zdD4i<8IJDE;Pl*vVQ5YDo!YHT8btP*QJo#-tMG7=GhR&!(86|g7H)fg|1w~Q$n;IO zH}-om#T}oen(nd)Vl5)ef3Y9E3>O&9=0~T-vb-H65rR z9~~R(g9~%{MnB(~zQ@dcLhs@Jy7Srh81PqM?zm{`nmindb!sYqwop3mE!( zF^DClsY6N6GApfxX!{a0?klIM%b!+8Xj@op+s(JNTJ(7Nac~8RQ%#TCkj?LGv0#yn z@8zR4bX*-S)Jd$%jpu~4Lg80KEy`8*j`!X&_K7*wi}mA&YD;UM$yDAVlAlfPH6gOH z7gvY6=-Su|3S0@47^ch9a>jc;u^Lk6Z{BmOvdanEe=BRGrVDg?ho(l@jn?_-%#%3% zXKZ{sK?hcvI=j&a2O1g?2gB66)B|xaJ?1Jzv0P1rv<}4_DxlnTOik0$p0~>x;mF!( zbUsD!kGzc}5}4To>4H|$#9V^Eq>9Eso7Rpa*D^Jwr@3QGaD3Q)IlK6x)c8@&l&Sye zKf;3-QjL3vS3)M)A?;jRH1)LwHxR&BK z)-o}P{QUXvX=Ybf*9`#y(s%FPt&Zg4U=vUW1)QJA{3H#iwlqp=-Th3L`mNG}iG+2r zs;Wv!U0p$2o6PF*V^TPX9UHG~UZZk-T>}H(I$q(WYe9F98EaR(1`x@vW}TAKMi$iS zFq&K#QTM{fkhp||kj+g8)YcEmM~|LYQo-CU=CX(x5fR}G5@&O|p4j)_=8Nu}r}i>v zFYFL>O6UTDHY(?f-I0lWRJ!4P)}MmVFk+LF!(>9Rvz_MKR>um7;}a65C7I$$(31!L zTU@k)$2S|!(D(39cV+uULM=&xd8sPbe=(AUUs3D(S03LqlWT|K|2` zs#DvDbv79ckjul_a?2p%*$hlwu;3;I3l)u%Iko84vHUk5@k+hcL4ZJRZ*Q;nbh}-n zOrOha$h;dS_J^q=aX3tVv3dFVxTD`vP#8A|lWeAXm;z_mqohPcl4b%g&#j>Xn$vYS zyo!jxtG4`zE@;_-$TaD$vLk({rN5$P$FtsRUH#f#USf?K70tbE{->+e`}mIasSYy@ zacU_-ui&;`8&y>mMV>FYHqLm?`+Ewf8*uQ6Uk^@$xh+0lHJPm5WH)z*Q!$3|=9OX-pp6Qy9nhtj|97UsbU~sZ;S%qDelVE; zGH>J;#qin5Mx{0I4mL^2GY#(%Lg@jD>({?|{+TiQwl?HC4l;IcCDqApJ!$jd)mU25 zvZo?*-+DbwDoR>III10v%zEob9jXzN^2yhXn>A0q-U23u*@Q;&-;&tB5aRnqc*Mkq zDS?;JRr+9#S~bDJ8c612FD@<)mh96Mzr_8cBY0Gvyw+8FJM>ZS`Qg0A6+5fGW=u;< z+Y1tb|*ANp?_L--`Xw>Bnwe@8Gnqhlj_o z|Hf&25`lEhUg=becMY8JFa6I0@3}XOYHXwO-F^?5)2%+H4wXC@*SViL`j_(b-xjNp zkx{Up>Np;s#39;Q=&SvQ)8p{OD?fkElWvf1TWf>xu2v85*1!T9`Bd%DQH#X%EE(6? zCEmPyciMi|e`l;K({B&g|1>r?CntD$Wd(1KPfKGYN}ua9htc>Q=wPD`?9bD$$J!yh zMKIHR^PKbUG2QO@_-1{5{l}z5;OtDc98Trkg9q~RaiC42)n$9HI)Lz`DJusKt}Dh7 z{;bzT{O9dw3iD-p4>Kgit()zPStk+G*gk7JTB(2*?_d3iw#~DD+$)otnwoxmy?D+$vuOQZr81 zPVj~{Xho1VD!QemB|_Y7Mb~lqLwR*}cDDZDTeKdR3>fM+puccs`v05ie}RDmICrUT zO;SJ}j=bEYepI>nDTv4A%E0r|EK{~sohIf;W}A)$ULdva7;O{e;VGZ7r5F@uupwwz&<~ z8QYq7sI}4m)KyJ5_3sKFy->>I;S?8tM?pn3_H2@%dDhXS#j8r3kFPTL5%mOnleM+A zVTSh#jhl;0l~Xc(1hh(}44?JlEV1(*suW3YL9+)bA6@7TG&L=~_eT^5;Ubq%-2wvG z0z8v5na4zb%~`BvrNJH0=FR52t!kon#RPBetUK{j_nsVVtO?nFg6qFg_%PKr`t|Gm zZ|a{mi?njTNS*H|yjv2BZfoa*ft>}&MfRAd)-zyjc~w<$ytEU}^uLYj9n-x5@7SJX z7=r}-@ed>*z{AL>w)X4XW=*=zUq!5OhT|M(w7;{F8AYbt_m@c5pMU}^s-Ag&)=Kc5 zpWqLIAUXl7m-$&)9UEp%9}F8^^EEt<35BlKXJ;7kSa)^`U_U(z*S?!2^Z&FdNl8cc zXWYIT(E>0u`vT|PxDx7AZZ)3DNG&D5wPmSfrU@VkCQBFlg#af2%pQ_%qLA&DDuV05U1sr9ks3+4x zqgxx!4p}fS?;YfuOZajPCBhU2uzgIoRI(#b6Tl^U9lKl9IR(Ds|(+@1A@81t6 z#mAGyvVRgJ=xjUqW|HEu^hR4tD|?xaf5Cm;|8T@e4-;TAm=3K?w`8IuJpVXIxv#&u zbq5P>h-*D{s-mbz3c-c%iwi}qdxtY_s1ynp&^#u7el3;QClvMSGc3L=TCW;C7^nyV-V#T;Q+6g{Wz0FignkkR!gw7T!+zZu*Cw*N0xIS0!+- zQ_6Pkdhc03*4EbU5DiG%#&u@$-;bL--^#bDpYHqe?#{0^EOhm;f`_>^1>taEr#2$v zYqdcH({gcf>BXcaCnfbWuw^KTp5Rj-rOU4dl1$wBDk)beF9Q6m0%if6i8xK@gtJZV zr3NcriPZpR1ffvL7>CFJcFL=*eKQpApkHPIUSNQ<$lARrAZF6(=Lb>bQ1Fle{{iO+yl&|3CU$}rJ<@HHm73}@6uZ-*MRg&?+ zFd}DH&#Pfc1>9c%f76#)@gfi8l*Iw}*vAkYT=0JyOk&BU$!3qx7Tn{QBG;2l9J9x6 zq!Qmhx-zi|Z?S*Vdp&==UKFXhDqYYY?eW;z z71{i!iHpsgO-zcq|2h>_sq4K={zt(#=JbWC8_^7T_b{}etwpz0a(|9yp!+g!j}8mh zyQHLK-2IiGw70i-Bk%;wwZmlawPe_}uEPj{3LTBa{GFbyOUTV?9vk? zjqLb^H1w)2M}vzg-_7q;vA$1{-ZXJH-FspdPu0omz^h@=jJ zu+?=(%Xj@VBknr(P!xCXr)s%rqqd9pl!J(dgM)*T-|1M2s8dFX#Bi=6u}m6I(PA(f z^-WhTT`>M$FNUq`dVL2Tp2c+RqzpzuZi#sZEGgxB$Juqy&F?>J{!`@AFVpnpO=kfa z&&kP2F_{l6R+EIrMz^?($UqW@BlYXlz}%9TwfqPCv?bumYj*~U_~9BNbTwiYBGoK?_V R66% z{F3_OZ{}ql3|NV0+kuxgWU^u>qQ>z_Nuh8MR?xPURR0bh$Df}b;&gJ@ck(7jI{c_r zuB#%n22K?7)op5jdp?uMF3KDmF`SGuPYUhgztvH1!I7Z$3Zp1!`%s&oGM zw{HsbER3lWdGmnv(Jg3Kj?W+Pg~hN@FuJ)GfXd2=m3yHhYGl?x6?G2b?~1VH_JBrJlpk z#bY2uwAVBRBs?}bgtgIb-n`lM)0tyP_r0c}VNtL2hyOZ%hI=i(Vvi3apc!=r`Qvla z^lip0gzU;uu3oX9(GuOoFEqzH%w*TI|p(rz~LNC=XmjxZZHc+CZ zppm_J z?}dRV>$m}mj-Ye#_iwcgdHh1{`SWt!fzp&*#hA~;jFMuG-^z^iU?P#Xn2gWMW8=1H zqqhh=7Zwy`Bc!QQfwx&ya1crL_qdfQ1tXN!%p6dF{G`f#1qQ~7mYH<*LXpa7q!45d z(H`eZlBKibzdF@5HR(WSE3#p=AMGw_85)LPb?Y`ZeBrRqKF0&>mhY#x;-_yBZWD3; z=iDtiLTV+XvgM8YQ|woISbThZ!=uj7Zg?`6z7-VQV)r*w1?{@KR+zciyxk_JuYcX& zNRf4X{H8dyS8|7lix@qeeNJvJUj(DHn%ZltkacGtpaB=w=oJQs*^PvNeZyu3Um z9xt?q4Wu>lZC!&3|mpJ)`XGybM(yzjw! zx8rQn#KvO`FpIu7d-9nF9NRp2Q0sFoie>zb%lqM)CmLilG{r?Y9WM0jo!bSYh;)39 zjJ*7Reeg*7s0t8-WXpw(eq@#hYXxx0s%0O&RDkISMsh!h?8gvan2p{h^l~qD0o;)h zc;QVi=8S;xo5fdZ)f>x<((Dzm?j`AV&u(c+b89r!zPx;mCXLI$iQVHO=CS#9vHmF0 z!2GtbmP}ukOb7`eQn8pYA_i^K4}$#MM%8SMphIV1+-seq>m3^U{BLV|_u_P$m6`cP zTUj`qm;j(Ll(Uim+=*`YpS^LcP`=(!AN@txToyXex^d}59qAb;w2S&I{Qd8l=<64F z#p>}=Qc?;`nz}vw1TI!70EHF_5pb&bZTczb!B$9!QY65}aBTRAEg@#jPaDnPS6V$6RcNuz?vdNx!GRE0+7R9B)}3N$hC{y*qW|CeO_9-zrP;}AjxP= z$UD-h{X7XUpWeaKfh3+_zn2kL_J>4sb;DXgswpb1ya)q%u>1SJ5h|=JGp^*kf6i-( zP$n%q>#D1iR(rw3dS;7wxqvp+(1Y@@$CK$FKD~7dhyjXGRuyIx)fW>67FZ~!h5Tf5vb?*7 ziShBWR|tr^pM{T4L*0z_+YFM29=pFqLP^2&E@k<5ynVklf$K z&oN9EHdTh`t`1q**)ObZZ9x{k_5rhcb+a$0ws!pHl5UnA5^PjB%OXWF0Z)wX0XoEc z{wMY4EaN{~YWjchhqJmXDJdD-beR(o8EJ3Y=I5<<;~%zuh3Rc2r}xibUhG=h9X3kn zzC545?DLNEQx*+Cj>3A0<%MDG>tP3x$U?y`GWQ^7F^>C#-nz?7 z4{U^Jr(ixPN+DxAlU6r3&$w|Rt?S^xJq0Ku9c$`6_W&WIq~VYpz7lYk->Q7Ay1!5o zdXpGD-(l7Q)3;$^O!Vau$}K60AfOl1 zBniB6`_`>chv^Sd>P;-)D$KYVUx&y*rLR1Nl~=mvcM_sksviecRE8Eq8QSWtsHh(e zMv#6fiHmNhq>PNZ81v)ai@C}mO}7WO-%`jbCpQD(2{ zi$h)@y+EZ?4U;CUeR_X7$Mz+#^1g&;HyW}djKWKlWf-VI6tkSe0=_G-u`{3nkZ;lcxpc4!Eny~i=)SM z>C(b}XS+QCOv8_;Lua6|ciE2d+W-3XYv}FUw^?+@202=}3P!3bD&vhGiu2$i&Uh^W z5I!~ronk$hB8=M8-35O9ef6|9dvZ--j#lp1KKhS3```C{|COy9y;uR&oFMS{^R+*} z@ZHzPUxB+Sii+2TAwtw+^LuQ-=@`gOx1o1;dKR6=4NW>fc{TxKQ zWAl~>OzJZ1s+5pFaD<;vSZ*9Bm04%*7&PJ{(~4|bFDczL_B@553C2KX@L(uszS2d+ z#IWDDFZY(su5tGj;(Rx8wZ^R>MyZq>H4Jyk)6@BA#C^G4Nzckc9YRkp~M z>2HsZ0Jsqa5Paf0*xuf47I=Q3XJcbyUd*a3?)iuQDwd(FqJo!xe?pL&U^&IUf|*Xl zASUPHs%wx|M-v^nNOh2oVss|vGeAN~=mVr#PfK4pfqP#w^L3Xscj`@-d56?4Pw zdI6Ugwv+5^#|+y=B`I z%`jaHbHH^ozH_ure*SlAfy~E}!&>l}M@1{WSoG4L_RD~2 zNW?C#*|*(bVL=B5B?HJbE>16Bl}%VGiHJK-hO)}a z2(H|?I9A122=PK8dun$BeGsX|WX5ES`Av+mutlYynkMNz8kd~h17dIBnT9&jh~TZ_ zyFOZ0$6q`7llK{gldrvyF0o8)9s8(Uk>clUfU9DD7a5_fRBCg@L8T1c6=yC2BgV2VXQ z2I}8u*TmiOKWmrUv>_H=G^V^u3%Al50)-Kt-rop=gy89*z3cg>EN}M`U3#c6nC&xK zY^%3CWa2iVBm{U8A7C-Y^!x=+$*Xl&QBg4=jL|0?a)z<$!C$Y^#qWfk#h1y8HK9FC z1%GG?0)#g_n_`e6tl=of7USKNUczZzA0MB`0RaIW&)KqX!u&4|>&jSS+nDqI{fsXe z_fp>u+MfIiC@d>`t(Gbh1vUfj=tI>gG>CU7)D8U7KD+$b0co!F#igahFZ5N2V;)_3 z5;d9wNux_@#Ov3nt5S$oWu;~h4fr|S#@&=$4G^5~M4r=D8FKHJV?;y3$@S~KLlVf7 z_4Z&D3m{O**q~)qR99>JI`K$#R&&=s9bqXQd8)g9M=;Fs{ahA9P$!FMGK(Wl$N$O%a6o~VT2^jqDAi#%rl(jitchS zmF?TX+u>Hho=klvHP3a3pNy_K_M90m6d}mS8ZSx4?c*i8E-+O}pdwdrwwGUZn}rbK zk~wD~&7DNFg>Ez7tvbDSh+OlWOT7pkTSHwj*QAC9u{ypubaC^hIjdMQCN$$K6nU{2 z$@c}!G?!mH*z`RvkV2b)jA%VSLGEYmdQQlO%=sUho&1xDiXlYM=4;Y~o@sYOKg4kK z>sUicz-0MYRY5_4A>9${M^E!Q4yHfwE9E=~8*A%vSm;+>cYE@g9Qa^A8eDR{fh5{u z;qzNx1vkpfnv>LJhnI*koMi|)y?~pU90N7bmq=G{KgrhB)0=>dWGOI4YaZJBXgjP( zd&Ap$1sw6|i29oeedAu!&+Fd-)3)|#p1toKMBh^d#4YhECjSL$^nI6Kki5Qm6<$q$ z6WfuAoz)0XkQTbxhki)bmyFuh99wg_g>^mxS|4=`cm56?0XENJ&>3HlbJH#sp1>Ij zGySO^tm-lVeX_qmbaD>#_jA@sya`?s8?vp@tF&lu+Z$12D*y83OYQLCzXIT^LetO0 zNN_1IhD`}Ng$QW`^IV70#1kPCQi765PubMys4m-pF+LFzJS89{9Bd2?-==8!3sfN& z#Rs~X1#!Flh%NGVgGZH;j?R8?aPZ*DE?%9iWC8)93^hJBKHiD|A3sunn&4LGBk608 zpt^`h+n1G>yC)_m-+|;d2+B_|3%&(al?!=u(x9&f1#nk?ZdA5^20M0D)jW(u_Gr+Y zmz!J|onMfaFI5sq`&EPzJrgBdil(EZqot=OkHZ!E=xqV8qi?@|{dxrUi<*ar$lAAZ zI_S8hFq%Q;sPni9Gs$KafQO?mM159Ts{d?4#ulb(BKrl31vX(T-bQ1ZSG4B{eoschZZC!}hUcA;{*7 zFiLt2e{lP)9uMUm1YtEWG%FYeb0iswF_51>f3orN4$YODh{{3wm>}8Q=XNMDQ*>Hd zn#ZjK<=r--kCuq>3&fe00K0zVDQ2M86Y3x(zIwWpa=#_MLOx6k0c1``{40&?l}9ui zGXCb|#Ah1P`GXL=asRK+T3d30f|1c&D&XuW0_4o6nelP9=>riGDYRfE5o8Q4ZN8Sd zw~<~tTj>^`L=?4v?19!Wj|=#T8?A?P_9E}pRP^KON_u;HL!XTmywk|M&*Pn8CW=JV zjihp&oc;HTiEih_bxIoCA~Kk3Fm%lWHJVN>*t zNJpH>XPsrE*e+tx%N3O|%r8OOubq_Pg?0Ws`7L$%3?dZ9>UWg2!M+=7zc{EY`6emm zj&Z~27gFGDKP;)KjI|R;r5a;-cC?E!)0YS5!5T>H z5nAj@+jEd$SaJsW#i8Tjf|(Nw|K7yQWqZ8$YXV++KX9WSw2WBK=O{X?#~2VCNW|%| zZ7bc*G*iH!2%YcVXAoA6!q9SC`I5a+#bTKB%iQZHR%yLiLSio%WA~31LZpu8H?S8p zIG07&H`NUM7?`mGRu%{m9DmcFU(t`!E+vnZ$_1{hn_G%eF7!QvY2st{T%^KeqJbA@ zQl`)SA0a3EYn{d7H$F$&VeViAvUxf+1#k4SVs&87HShRdG_cmSVbM#GG+u3G3j9qa zJn~@YN$JQXpE870ubYKY3V<}Rq~ZDrb#B%eB5m&>+i?g4;|gM99`0t(oY7slAsTyO zE=PVL(UDOPkYuz5$_{crR)69SLBs;xaL`^nh#2h)&JMx0p8L(9Xu)*ul?cfr{ltun zioT1pNGiU6r&Zu$PQ!F_P2eZ=8b$=ve1-ZR%b(uBLAyB`gaMV z(3V23)^n$x->`Ye1#CNIRIaWQbrAklG6l8yUCUX6Z_T_Ze)XkDW~45<)_-APrT3}Y zDk_F10PaI(?>)!8duFH_T_;-P6BE{bV4F^d*loF7iu^2v_+@SZdP!^*&3`2F3Jb?R zRzq_SJq3SD=9C9$#ai<57DSw{*yR;%wJVwQ_!94KZkv@uhj{PjVHhuhW0@UdUFCb| z*aJ^W?y57x+Er}x3i?9Sbyd}P=Pm=u>s4%NiJxcV)~Q`RJ&(b}fK=x-=H*xH83=P% z@_@QrJb*pevVwhi{53H4ZPA+Rc`WtO7-0~Kcd7OI^fI_t@(*6_Wt#^c9nSd@ zL*#1Trcn~fVq&0nxH_mtl(gz=#(OElkF>=h#%T}wxWAcLqWlv-0i*XaDFgwQ_6BbH zkJLS&*j^J2ZX;2}&Wsx@QDI zfoKh(ZCT{BY9zau-jW6gx5j3BVRq9An~ehghl|D;~!dwZZ%Utb?- zo>9&a5}ph3;hn#4dpoaBK+B+@3j!)UE#E^GF*=Hvl63NK0;=N@b@*;+YozaTwtS{< zzYOg77A#I@CfpP`1IF})-@VDFnr%JGdw)J@;Se} z3TpW1m4|fpyw|mAYs*t$C%ZS~I){je{x0bOV@z07c=*n*&+GvS^@JT*@(&&e-QORU zTY-{qoOquqbx@%|J)P6@k(QDe?%G)(Te|0Wh{D*^y(Y1$G8B84$o=#e7sjyKCTwmR zgjS~KcXoCaZ?v=HWN=bV(J;6HS$&hZFmBDS8TZzFSl0iq$0C;2^yYl2{?I?Ns0b{i^oK|q%nzlG>UAWPvnJ5JZ2pv@z0ya~ohK7bW z51ONv#K0!H6|VZgcMXrCXf*(lxUaZ&yNimJnV|x+ewyJJu3G_U88$)&iSa#n!c8E? zG16{7ge4~(7D*zs#rc$smcUf(xdHAOV%gitPXKZSlO0?2g;b8ohO5=T&8Y+raOm=F zt*wOy)9+4do0v>XUtUAtAC_tjxwSJ~7$D?3Q%1VBf(vB*ppZA09(Z=JO5HZW9 zyvcdIqEQ3C7Qx$ZHCMltP`m~;K=AkP-v&@uUFmx$DJXOYzGplaFnfUtPQ475w0;3m z$r&;!b}S)bVHfD9Bu|Qz2i0E9IzI82)cFLORu|HV*`_NWOJ!<|iY{<(MA1q}zlIi? z0RG~*eAMgL)}R(}85r$g8)rIE{OfKj=F$5fg+q!rp^&tmB7$1SGFw~-ewA{>#t zM+F#N3t~htc}Cc;-b^-?1;^<8seiiFZ5BC--6yQf(wrFAzZD-AX`{_J`wO;(rz z_iYX(Vo-UacO4w;xEhmD`~6OPjL`X^4U<GJ2dy^z;?Xw4*Zd z5HoxW0*HZr|I1r}5Tf{Q=;yc$-|!#||6CgJBVGVQ6YUG;4q?y|Vuv=4A%-alC+& z>Cr%-PVVRqcCfMNj59{M@D$(`t!Ol_7ysK;<`M;OsHdV5F};T3+&(0eC1Q|xaP=6u z;6%boRx&c8N#`+w!J@JA)2C&%%iB_KWfThuKcVSH>Pl$wShUT^7(8u+sYR2-i9Z}> zs%|Qa;i@M|?Lxz!WoXPKG zt?(ggraXMfEWjPr5+O6>APpc^?l~VIY1pB1<+)();-r9!^APe!Ys&+lf4O=$q1ITQ z>^M=KXTd(gZnZeP?>S&U=C;X`01V@zkw6sz$sGX_Ed1>3CCMHjX5rD@`fT6Tu)N$Q z96aCHXI!wCLz&g z`9kSG2Q9E_9Z-#?DSmjS9a|m=;JL-ZQ26n@B_FOcB#SeP_O_{Vv$H=YCMMpTD%$hO z2;hJhv;1elqhQc~T^Q7-Pt&5kjF}k&*o_8Cu-R}S!?+l*lr;pgQV92j!-t2Q7eS6~HF#ML52bK^VyTV0~hFw}*)x zc2=>%X6W(^HweWk!8Wu;U~2zM@P8{eQQY*XWKRI))M+dDZu#hx9BE%WH7Zg(O#K#G zik#gjl)NJ-NDml7?kbtOW-{3-D==pP7pix zw1U>*RTUNLLqZv;^HEQv{ACn-EV!?GtJal(C=u1y(|ZOuOzmn@DKzn3m&4Yq$+b_D zBfFxzXLdqO)gMYO&QC>+%fCeqT?2=_;OauU{yxPGl4}}^QP0|=YV%crJ=PPjo1uBi z;akAdd(z<3zr1(nj*jw@)AHfc*a)s+#`WTc=Ouvl{#~J})z4&hXK(`!AVjFrbdK2( zf_k*Eib+cl#3#?`lo}Bg6_Rc_v2J% z3aCRLWd>dxbJkC9wJLiu0Y^5~DNrk3oZQ6UerQN4BL*K&0($#2BUfX%;!*1|)($zLE20S?%6UE>ZtRgdLaGFR*F#!GsCv^TGG zJsPbPqiAiWfY(ed4Ni!Y!S1vQr?%tI@u{iyS^~Y3rafq=Tzm~hc8b+5-|CS>bJ$8) zUG{fn@J{Ak&x#bsw{tI-#47Ugx=udf^Sy<9hc!=_qg*?>QZD{OMfNx0IPcZ-_PDNt zRRSKBUJGn`O@!E!fE#_`x}l(eBxB4H>_1q6obTJ3ni?))pJ~xaJmkI!b-o*8U+E-D zs2i~)3YwZT9HnJoFuMcZ<>dQEo%~)qmbcj1ap3niyoP}B?!HquaOS$JK-hH(iUrsv z_Soak%&YXfo}qWshcHj-X&2CTxPt_RBgl)?dV-wR<2uBEZzcF9Ip#U#1F$O4aL5I`=7 zEOF-R3g|N1m(h3b1t~Y(iHVMO>c!l_4B|oFI9BB=cp!9$WKQ!oHeVB~=2H?vOSZ~K zXWw72RZ7u}BVvdpRlD3*jWdV;)Jbybf`(tB4KqjseaPaPf2{P|bMh4q$;6lGuYH*) w)1GZJ&Av)gNvs7=-YLz*L{N3)s%iY#C8b7uwSnJA+L#H z`$f@z5A1_~Q8mC8Z!Zmpn7EZjmYsq z*!8N$5#A?*3F~d;OY7KSO{QPG^M3EG+w@MFysDtF7q&YdrTI!he!QIPmAw4i9@&*h zAFmrd+@@bleaiVmhR^Sz!m!6Wn#OxDOf@>1_+({ir+a-QN3m|p?TEQpXxr1J%wd|! zDh;Okb=mzG<|pvH8di-tAwb&bA$0h77G-A2*Ij<_hq+i#kdLjJOXBIXo(3b?M-?1j z2&lv7#nsW$p`Gqs5i40-uL7N%G&36y(@c`>v$AP0j8%k&55ubIR0M9CIS1HC<4Xke z9y#UQJ6%>FXtQa+Wy8=}oXm`2#*+e~uv6i#o-^iWB@Z_jjGVhF<=LK{Hh0&1;9TKB z40Bj#ih=Lt{6@Ox8nU>R>?CH%ms;adE}GTj{_ zm8h+peq4kYxe^r9!n(i6<}5zu{p?YNyeH@A;Ke)quxY>d=W}v1mFi5}g+%wwW#f>2VzNLQXkSd(h+IA>6)82cwgKZz*h=+V;okeVaOFT&GQ! zf8Bb5A{b@?lC>>!R9h|^b83D6&4OFzNL<2{jo&6lsh?^_M-ZZHB1}`iMpfMcUgk+b zCR23H>Y&86SUCACKU&N|Pg6OvPw2G4i`RQ46HZIu6f~A4EMc3eM6}J4-vvk(w#?C+ z5=vBj10M4C%$&uYd7P0cgixf~OVoT-Kk?F>hkHW2kt((0dyuX`NOBzR0PKij3e_|T zgx>t43`=^o7+5lkc57)geBJOdTHfsmQIm)JnTdjssJ?b9Y?9?A+GM+$L6K=e$!l(A z*5Z^rz1yo!`(a0mNHo>7DgtNC3SJww#_c`9&ApGI^PpBNe5(tcR@AI0^>kdGl%v(h zBQZBp#i=l3MWilc#h1kCJU#u=y9ZSxR{G+b4aFj14+WQy?eKzUf-1Q`GKeLe`=z>w zmM58=At9N6!#xEIIR$OV@5o1e#(|Kwn|VETd(53LNoei21A4kpN0VnhW<9=2+R!V}l_ zs9XE@#lM}MpaUh8#~|JC{WW^z#9;-n5mi=XDYsKg_Qo6tLGS&F-hTT#>BgfVHTl_& zxV?T$wA{&hObQ}|U*XR;b;iK$umV2PjcWofJfpGd_&uu6)`QMJ(VV_}?JanSnFabn z!)=?rKRLizKjkU=m*<7Xt| zDFKq2{6)rQ6+gYRTnr~Ql`FDX^fAouE(&bb=E?$v+{s)F1k12J)wgv+gDf?b6W}xi zRuGQ1_FH&_*J<*I-$U4(s|HiT;3Zh~BXXxt+;_8RX65U4%CBNE+%pWFPFx@-;Y1`Y z;mgYDoD5kI;W%jgrtX~qBYZ@8^F2ECr<=A}59bu?yoP_rh<=6nU@r{F034`#>i39V z?rDaPW|VLfKrb<81W4NQnE{JO{5o}mf*9c}%IQyWw4i7gw~f zX3lH{6q8Xsgp5GK-e!Zu`S;0Y^&bUUXfSP~O`JF#SVm$ z8Uy}dZ1Ix#Do@IV9CP*nW>|j7R?UnO5d0j)K%3R7e+U$sF7=S$I9B2mWpH-EDOwMq zvk;%9t6<7?XVBK)?1ld&nNJ__dn)z_y(kK=%T3uze*n4dv}$0+H+tZ>&Zm(P_gSHh z@kgTgwDF>R@AE-s?$KZ{x&QG;8m(xoHFqWG4wFJ>2eJ^?KM#WCrs5$P#T5%j!e5gE zf^-K;w?VdA9q98~cWqpTKMzV_#+Nz5+XiCTkr1lKQQ{Ykq`2y_G6)!$>N6ADY~tKF za>wY}Lwc|(DCrnO1-MdmK&wI>Y~>`{N(l!=fNTOJWm~mdr7j1fUudSwXKCZsI=ZdT zzUrQS=+hqHGwW5Te|lnKLU^jGth99F)ox|)OvTrvbCQy#ckj*(%C2p0e_h**ULM)o zt{2`GnQxP`E&*ZlGP22-Lk5CoI^3o*1m>9ECt1Q)JhshcwX?L%d@3*c+CHfLOmM<)qJwE zvJwO(VHT*32L%qk zu*f{(r3$>Sh6cH$BnEe6;0!Bm`!$q3w0+|1sYW@Y@u?8}LD z5}#^`iS2N`VG}YDZse4zend?P?h6cJ(Nc%XTlZ|hgoj)(iJTo(s2X6=p3Tn5BTSE}M#{$ngQfx`nU`@D;!NmR~ zE?YkRPyNwNxdu2nqdV0Y=RY^FyF8j0GYzi8-W8kxLWaK%0V#q6p%RWdt z_D_Qek2=}4ubQw%c6WC>n@==6*a>baIv&SsA&bP^d<7{dtnZYFC&Op{-=Z`1vlI*Z zLoEu9EiEmPzf`LpqYIqWZe8`L7<7zLs}1@Oi-L)g7$mdH=)EEm(K=5L&ldgVsV>9e z2y;(FMrXdugV|>s#ig+RU1x2dkou0hvwtlUjbw@HzyRK$04r%{r zfx|&Melgg(FtY0C)1(ifLF0o`F?5zXb;82J6JdJ{|9oTo>yX{K3khKcv4)u`3L0me z10hsH^?h*uWoLGOjMQObbo)~Vg610D)(iH`iD18McygY@2RT^#d$2>xpyH!*TA5K zGoVQ#wCzZjJ)jif5VWJ-m*r!ZkvInC?wny0J9jP`M<@E5wvJB9kX>0slZpU{q=XVZ z@HdsynHdBbOkRftxxGO6&F$>`Z6~T)N)|vk!LKP5!pEnhcO#=Kf<*C3A7)nW6c6N~ zP;*FB0gUzaz+DBtNt`LfLGRD2RrC%#c8^qN3{=McrKbCU`OfRE5Br-A* zo)ke(g4OxyrIyE^j#TCatAW){Wn^S@+7+kt&WwlE{6O|*5f4HDur6Y$MA8h_&N!N- zEeQF_sgbHgs4<)?9R3Z8AWRKc;LM`6XlD|CxJ%)lwON49Vv>?NIBATPye1@)f?dlv z+1c62DWV==5PruHqK*-RZK~(=qHT_jn!+}5cIP=1%Z9?#(jst&Qqt<+nM-J&$CAs1 zs;mpy=3EC7RE+s(_xXc+%$r3efk2EKkW*XywU|FRNZxDFKRs=IChpprSj#oErz?~_ z$+_#W8$K#TX9Zff84vk36H3tM|jX9ylLe^Iq-!cyWRv9z|HW5LVbvLPhlS~ z&_1Xr=(+kUzer04>{p`WVoLd5x8U{l_4BT?y2~CF|IyAMf5}~n(o`No@r(5|C|K^Q zfJjR^K1Zo)B)m3|ell#2XeToZ%a>ToL=Z>(@lwq3RFEX!mv6O8%{y_6t9a)HM;1jo(uZeAIOaN{Y{XQ6WXCU(27uA8$(XI+%!HZqkuDK#teQyz+(eXA)Z9WElq$Ih zR;;b94V4Gu9k3xth4`Fk+@Wau3jRYgfPqtqNKyhsP3wR~C+o9pj{sOfopA8%xpOQh z)#8KH(#+VLJx<$J%+kQp;%I4eC|H7YA!w@TKuYeKs(b%*{+O|TW=@V02)nSba8RS< zqSC|UI}>zNSTzYjBULDzrMcC{+TV~ex~);VL|GyQb2v6no=gOdkj)(2=>SHw0gUi_ zn1&8`M1Z6(zszka?93#r0WP|^P$f&C#fq$4Twt4uwzjroVKpQz$l|IDU{cjge+b;< zHa*Q9x^V4@G705lyIXsR0E9vz`B&gY2u#9lqTJI88htdhm?%y5TTTq~(MRA9nK9!(UlLC-0$UG2*yZyq-6Fuhr@a6M~(qRt@#BV99Rho&MD6aohGQA zjEahKQlc_$rVXt9Pw&jUsaoZ~=o9&I|J|Wm(_m(T8QK}JA7V6S7)2(N0a&9)%Zl-* zsIe0g=*eSuhYa)|2CWb3mE`JYF<0O_nsqVPx+gqJ6wSX8WLK02ANc~|=NNLhw>G@Q zXvPeP3XIn;LWO1A$RXo(zH}(NEGEK6m|MFDFAhsHqTt4dP=(M$`ajK45@ftJ*f(52cN@o`0!!yB2k_PwI*l4byqwXIm7+;tsL&40){6Vt!(%qzlzK$$jQFqoVskIlGpY z7D#!{ji1IROqa$bfc^LbSw9@jLjHW_d6V|+xwtq9ro(dhKzgn)yW%+9K9S%O=P&QOk7_Rft*v{I3kTgD zs+bMv&SNBXTi0)|jU>Svh6uQRm~r8qxP1(1B%~05!)7(K8&d}vU6JTqA$(~}O z{lpkXD``m;)hd2q5Xbhxng__9Qtn^}st*GK0wB0SC~;EyOmmo_vmIj1^I27N@Sw8j z2oe;cXXngOnWNOqN<|Pksq$0!K2lhWnsRHfL}-xy zKlN4fTd02hI`0H7I&t%hQ1SbN_37TabviR5fz_G81i=P*q)VI-=|fOZne(I^NSkcv zz0y4ud@?bJqLeshU=&cU{ChD@aDK%){SwdE1RxE>aSos45U>&JdtJ;Qf~RcF6s>FN za>bqUNWK9cFBvQ)Rcf%-0oeFAgcLaQ3oqM>5yJG+z;w0w#ZESO*;dx=0}`ELB>P_y ztr@<{&vO*00jnXDujXpX!HfLwNCm+_= z*T1Z5Z9auIVH_X?*=pv&qIg_nx_Nh1|g5V3Bs? zd`E(rwhL5LhK8-2)L3f6;GiMDSb;w9JE+2lkwnay;qMt{OVh4p6u7bvQze0S1Ggb5 zDe0sXdsDj!p4fw;5laqxbBhq*FgQbziI0zrM+F{$&Y*_H&2vD4`B^2SGaLW{RF^YO z0n%*QLM0BeVT=ca0OeLMBoPWd7Ihh|S3FI`52yiDgipJ%IGm z3l1y)7eloeB<1gQjMvA)s4&vK<*%K9BFSd0$=%8P)5tqjFCg#C=+o!)n9k6e7piW_#5e4wGTR-ft&;)-2>^Fc%%W3TLF1kilEZEEC7mal5NrcLOIN{p ze5$ydolEIhU#tZ6^=+IlYyLL4#^v?x%}1l1aU-9Z!$v=9ii>t`@k*+^otw7zmY1)i zroX7}If)xtFShqtimO_Cy4$cmqT^F@fb+ZqDnRC03oKX>MA|@1jw-6css%w4JfjX^ z(=Wlbb9x^J&?Jc2c3GFJ|6wOz_fbh^@d>-k&iC-$ySB`KM!Gp()qT`dvV;p|In?b_ zuI{=zyp*_BzEjJ!^KET-YvNp$u%xq2u?$mu?lsS~`9}ywHDpTRnF6l7ge)$H%z_Ga zI%MS6)V)GMe?q7LrRo~B?Js6#*jD25UN)%OnW@^T$nhE%JXdESr8lzSZoYNpY*3ri zlI^8|%^H?UhuX4{?Ron~ix=)ipOz)}8vZqzc7$bcNDS><&@J| z#=XAE=7A7|PM;nRqk?Xef%$lE>)esYe%;q|kxVAr5 ztPO95S8jCY?1#m1|YLpAQ?kd6%naUaPs) zEN<{9X!y~&;UBv`Qz}LwfJ+J#@&v9~^g!hfS!E(j%*O6iNX-r&^IJkut3Bc$GO9HM zay*oA_1!u~2~L*x#XPJ`)+f}TT?=upk~G>`jNaX>^xpKjDCv7w^^Uk!7>Cr6IaeGZ zR4-qjNkN*jSLA_xPyfMTtswwMKqX?b_SK=W4i~vSl6IEUlD0qXm;Di?uB-O&l6>Z% z+m}bap^il`~VbjYlrsE8R@s%QLJm*kiC`M)vS zT%C*CjH_CY^Ul-r(z`A_q|KAOmVVuPI){$)!g5s5oxi43m8aJylSH6+>iP&okC}LA zkhKOA-QzvjUyu`^<@66&H`7MskG_60C$;Ox6WrP|+f&zf*I~DBY`Bw;HD`&l%gg6< z-r4HUGi%&YvW<$}l(77h^DHZEvUWy&!vnRus{hp*YUWx1Dn7!nEqd%MGh#%dUFwMq z>!k5rwm9CXmE;0TR)&gm6;s#3v$L}sW{h?>ykE4w{Jp2QH$^*RJWNalX{k>T6J3H_ zSlz1f(@~$p#~81lmuUW=rN5{jmZW2`V{dXKT7d9xObYoKlg1EjVWF>_&c@JjJ4}r6 zRHQO6s4;O8Uz=~RDb_Wogv)IBj(E&u$sSi$5pEX+gx1rFKgN*tZS#SE%ctu5UtP-} z#)VKroI>&XEn*v6UxOyNnVlzNXh6AnxyA>A(+f7T?7e4vjSLM#K@(MCR~ub{Zrns_ z=%5ERXyxhs>6zl6{(WnygXQ7FhgNsnT)V_r<>j;Z4>c-L`NbmKV1YWm3@4pnVF0o7 zm7DW}VxLTZ;Ys$~e3Hno@N*Vmu2{ArKYvk#+f;yXLfLZrk-gU!uC1x0ovC*rdZ|qS z+`)|5**yxy&i~AAh7<`Z3#`qpacNtK(wx3fj%ll3aG|ueM!_5{CvTd`uA1#84MeHNn8@GT9TnLbog$Qf z;jChvKO^yCb$*B)RdAttxj!M#7mE6!$-u}!CmyC-Jn)FbTWhNt|E9QdCCk^h?QHMX zAM&qj9@457eSrubxO>N@B2(l)szek|fq=O_ZxS{Lp0a{)R>L)PY9dkdEO%lPN6Ip6 zYEPET#@Cdjij^LN-JAS>#>ixVGj67c_^!9uA0~*$o`Cn;etL0e1o&EvfB-2ns4oep z6ifDO`b*FI+nfD5GT-jgf4J<}w9H;UbpjU)gHi_R5#55y26ZN3%H*53?X;O4-62euzy%>+9EohQ%%@YlP zbJHTdFls7q2gQKOGl5rxQohXdD%}jY(ASf8AcM8Q(Ifki0J8oTz&WF)Pl=xM!HADi z?7wBiq#%o8qz3A5kfQ%7+01*OAav9q)am{LrkFlb`n`eu=-F>h{%hrv(p8J^uFwmt z9xIEpD;4PJ>2Yf0FZfB$vYv$NP+aUlJ&#nF>OBPuWbArgfmFF%Li%C}0!ca{Bi>E-U#i zEA4JnZAI@czJUHD=f2dpojE=$8P_Z3?%Hn_ezOb|`_XDC!w94vAygcPXHwvyoDL;i z5@nJ?_F^Vy@V^>8huZzYSoUj;R!=7N#2W1C(Z2a+Ly(7iU|wD zs6aC#_75lXdmva9+I*Bu4gaSuNQ~y`vMY{^4*mEoJuR_Rg!KCRcknR6W%q*vVgz*J zo2Md;O14)AMpzg!$kZBk^wP`kVwFixaf-2p&OlDE@&b&M6Ns(k$O4iYm>W2%(`M_| z)|RiV`{LMUZIT&lKzG%ThgCmDal_xke7SZ)#kdhysaTuZ#UKubK#T&a;d!R2QP>}V z(E^Wqd{u@1LeGXjy^I^=Xb}9>Vquee%)VQVzFWo6g^}H?SnysbAlIs^ZLTfo7>8-& z5LVSdeNJN7R7>Z-z;|4NgDx;B>&7Yju%K;nZFT6ei{GlL6UydGGmbGFh6RK>WOu#9 zWMz{m$XGy73mpb1dcXHq|H%#JAMTt%WEf-D>_9h{f4P1E7RYREZ{w>&-RRw@23asb|t(J@B^v1 zxlMoA@3d7(Eq?N+7Y?veb$vHiJaQapBv4tT07&K@L|VD@m`V=L46}Zd3}`G~2g+Uc zSNwUutM|Oj%)Z#9iuDV?*NK#;DFl;on(Z~CBBx3I6pxDR^4n>&RXZy=yNb#J@TRXc zF_s2kRtk=hwr@LB86$S$4UCi{zSXFlaTh9sHpc7O&W{s|hf zDjs-Ie!C3Xp!TW64Jh)Jz{I*NcC&Al`Aomr&sBbsdmp)0bm+L-r~48>8-e{(Oe18! z2FxqGzATXc1zc>b%6;+|@O)DflivumslDF;&E+IqbYBD|VmRw< z``uOh-5jp%POj~h!AmjtpP*au*c@NH#WA8tsHa*1txkeHc5D{&VEm3XR-P5mM5HpJXbUTG~;OL zO!j8m8{=;|+%*j5!XN)@?2o{FjbFKo(qO6u7HALFg_qr%cy(pnzI{rwFPkg69=LcU zC@A9Obsv7xYscvi>4DCcCLYM6Ex|tLS_bMkC|!DNVbMkG%0*!s&om{tq2 zm{TO8Hn*woJcs#v01cI6$?+Flrax2OGg0{c+w=pj&AvvN^(Wz8W5c4PHieR%jhU2@ zg~>1tK4?BN!)zT4B~_CUfvpO|EoX_*xL2Kb_(jP4@Yx@fg^d1MJmPlOxoXv>YL%TZ z=-9X*U*`c5u0&bxa(}CWJS7dZAQC6$0?_aBLgVckd?&9bUi`Akn`82$Uc~2nMAfoN z)$ON;N^bWWI=9u1K;d}JZt2;-2uA!ElY$0fxj$*T{{a$)i4EWtaj%B#0vDh5ie5xA z_MM9MnK}oKY52f0$$K@7_`V@sEA4oDLO|0hWX*)8gcr9bw3JbjOGj;q7?|&&v@uhJ zK>qRILdcGpV#=ScoGbtQi|-DCkq{6tQZ6MxbmWvypEA;NQ&<~x4tL4N*%b1Jcpx4r zy2k$$jP{&y-p?Nat<7c?eEmjYFMjj&;*q{fhs#{&O22$>hAyX7pR*OAgo^!Js9$0a7ud6LDDr`o*ElhOSrJ|Em8-+-V>zzHi3q} z@N>>qbB@>Q$ab0U+Kz)!^x^-ZbJ-hA^@`|7EVV$diykfN!CMWu{!xL~!8=`QRxu8p zkog{b-Rmoa&!jMlA0?u`)8+n{8i)%IkO!T5Ni1bB8JVJ!g8Uf^am+3D5zG2VD69wU z-CGQNep9_nW#$TnL~YXU)+BvEj%<0|aD^wO6{W%KpUhA3MnhWqEEv&<)_esNY~z`@ zHg)`>CNepbao)!*5V)V<=1aa1YJTSvF*)R{)Mh_K+>gb$!ITVo$y%unrf-^SmU%^1 zetZe%svM6pP?e$TuUJZ0*m@5oj)%$*k2-f%lllMrtc%K->9c_^de_SNT!HzgC z+*;Ds#vy5k09G``QTrhudj{THl`qTX_iWPB4zeHCb*jT2)D2K9QBq zaGwt6j}foo3<9#gJkgE)}v9t11pqqqbEA)~{d3oF&(KY*QC=Y{9* z!YT8TWRMeG36@%NT^QajMS4}#69R%08EN?u6r`X0dr(LUTc7B6KFv5yp2%77n#B2* zK%y}~=XfzbKF*`8%FPYM_Ptb1$4bXQWF34_$mMRd4N^5f*UxG|ePq_#t|$sZ@#FjB z0gOCp*}A*0zs=d1&he2X&@Fx}wCO#X6*YV}u*4t2Pv#9Kg?Uw=LG^?{;~Oi;)St-4jE4+n1AFEFGd1I-s>=bVl2<5H(Rhgv(W4rg1+TwYB%Og zst7?2I(%GPZ@9c}&2x-7HgXcS+RehHSG&m0SZLoM#qGP&uFFQ^4!C>GnsF`V_q0QQ z5r&sFDP~yWOTGr#PUgoO`kjtJskdL2z$q7Yb{2MbD$o*5HIRTGL@?wf;tqU48|sa% z8Dv-jJ{1LtNmME@@}TJv@}N}eE!YdfP+ZWK`QbfhW3)MkTPRYV zH|tKye19Rk^F?;2ZBUA}3U=3Zx^*t@um~f({`*mdCpcAZ@2-c( z+Wb&XOM-tM8{TuSF#O`?YyknXuPD_6giChDJ_5fuHF$|Nr^0hhF{ihM)9fRsNC+C* zP~B@kNsUFo6h`%HU>IJM$4kpDNysjtMzQk*IGOj*R99M3Gv{C5t&0c9Jj6FU|AdtT z$l0ihjuT<3Tx=!tdYrWHxBb4~J^{%z9F5yw{g<8_AR`BH?gs!@Wq>@<$kKLhuzZz73)f z(Tc&rJ~2%0FLqdC?;ipyJTM9vX4Nz2Y6fg5fwp06d8+Gr1;Fs|Nho3Ok_#Z5C>?hn zTasPTl64U!&^1g3`g{$fcvz?v!5cMpe#89w(G2k0Q=}V*$H$9qWZWDdw>>uOwbbUD z1>+8P7d(2)d{%*p^A&;x(z>n3!_@Z`r9eXx6)}Tg?5a5WX^WOLnU(ZFpuv10F8B$E ztu>sh{QfM6b&RgYZEI0vH$U#vKyNDm)M~&yCj@8AiqpWcMz)7Wwmbf@$eOP!o7*CI z-|dyE7?9v=_ujJMm3m|gt1Hfm96#ysu6Br)Cj?PZDB06!XOz-;0Cs#HnNhEi?{-yd z0<|%l^x|8dsvlfCwZ1>Vi9;I`2*Xx~oHr@1SG5IOyC_aT?T>PXf+eOEjGoR34PN*AhR=jfJ_HWLi=@a)2 z*O8ih=ADxyEDnpZEkS|oD^56|XoI{kqjv_RgA)N5sE6Vx$HfEv51=JqMp*EH_!rt9 zD`B}aKM`l|UovjD+y#@TK=Llz-$-MO2e8ltuwvGXtom5KC#_(3) zbL=8*$z;yTyE{8{|9s#ayJlf=&2aB#JE5}RBnVK?d8zGOZ%4e;5&>c#8|AcF z+7M`-&2^yTNTX0bI1Rp%0W{}NVKgAtXBf04wRxXvF$Ps3a5KgD9t=XvAJ95Y8snA6 zj5AT(?X#8s5z~@jrtkhu+qxD-id`YX0Y5!gV2_i$H>T2d!Mhc|O#1Fj?*2x2AV4{j zGE@YiTGC*d6K@RMw}%(DhlBqP49-|g;?Ol7eTZHmypZUphTGw?z?{vXn zFUUw6xX}RrdaGD!kI3$#i03D5&Eg@~f%IJcW5%X~gc0wR1>fDxT>%1}>+s#;q1A9f zRAY5zCPI`G#i4VT#8j56LiV#Oo0IH{=3QRyy1r|Y)0;8bPF4M|^=^gX<%4=WWv2nL zKo~=Fa1EqH2<6si?p5)g-D*nOYVt*+C?dTxE7M>I%Um$J(7xHbyJ55&K6os(@3L~! z0pRMHk$MbQC+S49=F1jj=szldMF(3z#*zqjQ<9q%t@?oMoLexw(Nnx5hh|~So^>O3 z%EBL+9hvx)p{50ufrwG3hcS)z3n(D14H1l_33M2~pHR7!Af2=|cG44;S+XteV@|sG z_tl{4^B&qQl%6=b#q^RoIPcI!h(R6Aof^MHJT=rA zW^8&~25QBFPA#%+2~>U$*S^)#k8Es%N@M{Yv|B@?lt)!U@G?vYBM^}?LDguUFH_`| z=spoEvfFL6-Hij-@ag>^bRr=8-cMLrlHJ`cAXHs)9Uk}omSbdg#6&0|qJft#N-EHe zF-WD9ef06gFOr@$k4v*3WN%zdr55=rd^dKQ<|%U;XNTP2kTKt*lk)G)f`bLRW?zuL zyiT7fj6L9RvRltV^c__eZM{$ExU{xLuGYJ3j&&pM&5I(dnWs5gdgc>{M#u|G>#gxm zsCaxWNs$YiJHx#zp2eqGY)cK@GBs1=N*>7>y1O}*r=U2{UI3K6T@T|E zB4h2B7Ib;agdZVOqFiud&w7HBV*nY+KrwlJ1}Z(BF)+K2vwe9f&v4Wg=8tBd-PBb6 zXoMMGL80}R2+dbY@~53cFN2issa353g=hd6EOQ82yx&?7q4Z=>>T81UH~O77U1SNS zn1?t2dG*nUx17)alNo-Rr7Id6cL0i?R-tYR9)5&eJtqqVRi>Lf;GC3U>S{&nF*VWwUgsy`5eZK+ZlHk zjdog$-h!nKiv{Qj>)dkbhJn!TL9vimPrzr@@yNbX&N%Jof5nM&E$1Wb^Qc|sm6M9C z5n>q->B;;*4{_7KYes)}PXH_#g7|kMu=U~GZPPYIRERatB*W&vazXF8eB;_z&9tuA zkw07SC1sV58Awf z8S}hUYdp(VeFF7-O-au$7XODMIH>u8&$JRx^3e8-w!Dx+otOM;T!Px>_^t@?Rxzzn zYeGuUao?@)Y53iZULzQ}pK;wd=`(sV@jM{kqmXHH9VaFyckj8m{dhJgrCa5@6~61( z+TK19rXkNYeec44M4dG^?&Xtfy7w?eQHUi%FzMsI9Uhy>t*sQ1rXvhuEG;yXUh=Jk z3kf~@EME8`!6iR=@#|%*r@C?WH6C<@ zL9PRsLjDpMLX5I!(~)7<(_U>h6uNFx#Pn>OsCnU61^|=%&zhQ=C`0|M%herQtsU`R z5HUnLK#z~sAOm}SMvbmQ2uw0inDj{?xLC+b2;1ZFx@+nKYMwR2oi=s3A(vd789A4u zoh|j;d`M8guJDT49r`Dgax&kHg#pkL;SW?3xWEj9jUm zPT38m#(606#0?|p%TW{cZ~ip-966jC^O&=T+iKMTR|V!&12IVnNt(}Q)uJ>Fn_F(a($08ME)+=b^@)1G$r3YOLd%YOGf_iCe4Y`?O=wR;^aFHe**)?{j? zKu7QXafBv&7oh9|BcS$cTftQ=;VhjkjkmKAy9e~bf1Xg{1VE$Z7j{*Pr#4Pb`A-zx`6R6}?MI0RwE?e{L2UZ5F~vGlUMcw63f0b!;4_sZIce zDUIsEfS{N|#{fg zfngQUpnN;VTR-kLabDrZ!|@tIUKzgUW3tSLoTvNE#~r>rI)|scjmXRpn1|f9 zn&-&u0PdN*tQU?)eoU?t+L6REj8BZ}f%b@%_8fbKKFsu<^(=+j3I{2%R!(w>We6o9y-_S^Y}8d_y!iCmdOt!Eui@BRB^ z)Fh%Jx^ES8aB|Ot_;Cg$?VgrY;IXMA`)JTMFn|X=zQ(7kO!_j_>I&sV-!%{^a}^*x(ZzSS zoI>AU1@^6U@EG=07C_zFxBddl>j1Pq3W)Zii=4}$dl;XW)Zc`}^7roo?1!7P^Lo*# z!VlA#MY5ys>Wh?F??*}F2}6flNM_g6#qVeaVGg3kyQKN@rS?Ej-CQ>G)FdEnK4x*J z@=FBI%hV#!SmEMb^!7#SCjM>+Gf|q#IOqM-1OZahH&5TT;q`WcOdO8drq{XIVDr_k7Pqdp3!!&o~twFyQT9l zr|%6j)vvDY?u_hafaR6Z`~Ikn9&g9wc0EuK^@TntS95}YVSm1POL%`&9^VQj;X;X@ zd5K_dE5W@w*jo$xmPWQN`Sh0r*cZ*rM^bX+o9 zz7PeU@6G{1#RALD`HbuM)Jw%=pi004ZYJd(8k#CwS0AJ;?F@>Uf)$RxUdbO?)V^P( zrv3Ejfc;j3{ZO!b#kV~$KIjS#3xvdb5$R~$6)N&u8p=8j_e;mkVJ{(<>lPOR z(t~t4h-e)rK4|Yl53>>IOx-xtaC#BQHwyBYdSkR%d)+TvAJa!QiS6aDH{J2x8G(d zFWh_fBr<~YnNLnjPDbSf1H{oi2j3S||Cmb`sf!mWdv{A@;BCBR8}zxpdB4*d9uvt% zT?)_LC8$u7n!ztj^Aw9ppkc;lv#XPX$`o}kFr6iJ{QE0k7#we#SJ-N_|8-TMTT6K< zFFxt`BA>6LH=vpwHMIW@pzIc^egh|O__%xad(m+$*ACu}exk`197IiaR=-f2XBbkf zrM!Q`y~0-6N}PMbOiDs};@ZyW#*ao>A9uk-#w*405j!*DzgXz>ND(Qp2H zAeDP9E!yXoo<7nF4ywp2$Ga9K^|ZLA2^&Bw(~I7g)qats3;2dz7MO3Y6o=|0Wa|3P z*!4u@7|;i0wXcMG7KF&V5=BDZ5y2i&L~ zEN=R=uy9c{4Cpsv&p*L}aMNlt4#lG4Rm{(Y%um4l1~ru#P4+z6IXAdH`zYuS0R?%E zhe45wq@nE(U+Rk!X7b9PMae8i6_=042084rc(e7LYxnyXlc(_hMvCl4%8QZpgpnpr z|Ff*ej-fk70IFX;Ll$OxNY(f`BoppYxp|IU#Yr{wXD5V%K7anK0#R`V$*sx`%N*bd zznH%QgCOTC?+z3RLfg^>MiTcpy9_2_*oallw4TnE4ldOZS%qcK_PTYN1r~@~~X{o4r_%>ivVXFNyEl9p-s+o8TtP{DI6j(rbfDz^=nPv$L}!?Fsk0 z%NCVeSbLsR+{X|O_bI;M0<*DJ#Y&dFG+>5|wIp!3N+H5NtQirTiEu&V3xJ&qI);t` zOS%8}9eVNCv$f=CxqVlzTuF*6jvc`2_SYnJ0H2n$pZ^g&N#RUsv~sEJQt+&E8f5nE7m; z?|01aCRA_!rWXj9aqcg_{2~o0En^90nmLU0^Di;`J#qw=0knBas>ADA=5JJ34hD$e>XsG}GfWETT1#W9d(X_w(;=WmKtl9u2_TRdKm%Cr7 zT)_O=V4hN05RpJlkO;UlIRv>Q#4y`4GtCbh_fEW8|C5UH;bvQL?o;F|nA^LX7x_%F zKH8p0mX4!3hTq))8k^ldN-;!rJYp;s3$n}IhF6P<1rl@`14OZ0 zfN;+<`Jkov?xdGwuvIe^jmWSHYQG?NHO`0!evS@?Di`V0pQ#%n)i z22_O^e*uHacUkzGH7+ZioRmVUoj!02#$s|1(7T@N@z)DV6bt*EHzq=aD`gS{|R1l`Wje=Oz|`I>MfD01yKO0sQY0ur+>52oy@7Z&!YQWFOy@ z0BnXYT!A9&#r!nOP}W#M_eYWe$6LX;DvJD2{s#rY#Zrx&UNg8X!Oacizp0PUF#D*S z72LV1NkOoz1{bUjepg!v9T>aRk;6SiPq0>XRBj(D;We0llE{3xWDrJE27N0 z>+0lNJ31O+5Z!EHxMK3ONQdRUduJ>xEKD68#h$fI9M+1%6pF+h>EP^gGGG&5Ut46H z5f?uKQ-EMUS(tgq{&iVw`Ws$RdYRH#4n*q5$a(G5s%t`4M{m9dEHrEbEH zvkZz$?O;|(4tDTX)d>F_F1^AIQd3hU$CKd7pQ*L=bihjfu$qN>Hw@Y^=mvnVY@yU7 zCssajHpd+mrdH?&bC>|H@aHQ+VU(+hxBKt`iexUXa2}2g_bJxIuTE#Stgs$G9u^xL3)AT#Q&U#;uy*_xGzKXSK?eKE zf_4g~zg$MWpKe*f-8~!H7Ft?bdAYg96+-WHDq-$M7)lL{sTNezft(fd6NhA=5M_DN z`jV=eS_4RRo;BwV08hAf2pUIMl6k18XPZtYEeHOJIb0I1SbjeVI0)mHpy5;hLx7h) z)(C!cBRt$^IR&z&;|rLBZf$Lqhu2{fx+3sf9@SPr8t~*Ef*=Mm`T5DSPjPaxafyjx zAZOdVRw7Y9<+`mQ|IosE@bM87D4?)5C>!jbnQI>N0LbF}L|5`~BPOd68X^nR(;Qts1{8HHu8wkP95T_xGL!#ji zCXq=0_;HHrzjk6(A%tP<)-aQe%53l|xPYY24P`*F8URhj|6?046&Q5dplC}Mt@@50 z>H}UUn6WS<;;zKPWHBp92uu{+?024QAAEvNiYWsj$keSlk8OV)*)H=Xn9tMtoBnT$ z@Bk>w)a?b2+;Mbt96(n`KzWz)p+KbsJqti}V_|#IYU=QF6n;YPgapCd2yH1e5g|^9WJcdT!v_A2y+afj{P+a8_>G>9 z@;~>(lxy@t$(OKNvh%lOAjZ$b^)(3M6nmo~Z2kD&_}`e2pw_q%tK+!6(z{y=?Sr8w zxc#!WZf@sM>;@c^nwC~!MUP=LFj+-^3uQXFSU?@zo@WStGCJ%1N!$JBk{}uyko~{) zg2=&cLjnS5kZXN2Wrv7|vXUMSqT(8&@3IDp?PVDl;QODqfXyg^AB~8K39>GHhC6~` zakh8veC>y@iaj?1)WB^sPN%*Xp(y`hE7aSIx@mA_>YPlx8^<+1d%sHv&xgX5}e*4Ea_fBXjYEj1q!00Pav3^O_rAWXB);E*rng-S=Yzv23+?V~qhH+Ux1}s0{$G5D`lJmqM;}_zZp<8Xn$QQ*#-9F$U%Ld0=FhtAT+N0iXhy zDFAZUh4F!p-7rX9;0s=qB=Ja3H6M_}oG(D?)$eMa&BHTmjOZVXv&OfeZ2{ztIfQy}iI`ebUN{G2xoETmZ% ze!R=zs538`IrRSp#%h{xd)Ul-r|v}|;|qb{&6H4l-t%i+FypyY;xwWoep5AL{`mFl zoqtl&)YKH*g+~_daGX!{;rRb!>%HT8-2XT5yEI7BqLk>g6s>n9Q7I%X8c31$P#W4o zlvz|rX^FHPR2o{eXwa65QbZFeR7U%Ez243_-|zSL`#m1#pU>xv=u# zNkA5H=Sb-JkvFzwkar0<<_) zkyVX}DPgARw9BhCPI|}INT2(^SLDTxcN6Iw66s-ggJQEQXsOoSc?;;_aa~fhs%Get zrAwBKpsBA=8`WC*iJJe6Z6q;^f$vEfc$fsP>fp4~&(#Ql1$*J?9OM&JHEZ`mVZ&Wd z>YQ_f*WEp9ag!5?7e(9rHBuKrvMEb~Utbh1D_G$19bVK4S!;%I;8%-(zB#P192e-q z?LrvM-se|EaiHiXyWNGHh6R1-VtBTWgq`3>>+;pZoDy?pd8gI-^(&DI+~)E8b?bxtFUG&yb4`NPF?gC;o$LO`|Ef6q{RP2Ou`K z-2YvG6OoO%abx1j5-RD!jct}{aM;~gI=DPlm@|oV`Eh&hcEkmd-j;5g4we6p z4^Wo}T!?HjW7qxmI;8T0q*Q(pWKyYqdAUkw}BaYP^}C1&7{|IXHf8HgEd zsyKHXjW`h`Gm>8jtKGTsxlqu6bHo13pBLyi!ZqTL*@glUKROHPNe(0R@px9;#UT>k z$<-y^K7?N+-ZTjp3|Zi_Ci*L=HfsCe4x-97pH+Xq3BUY}7l*PG;5Fs_}yKK1~xyVqn#V%0zc{R{=nk*J|iRMpqUx^_*ak&2Czig zw=Dlsf{U0s+1PwQ-pl5=nSgY$cy;rg{TvlmiZl1ir|xfnfWrY%TUmepG2)K@i=z=~ zKK^{~z9qpkyg_8y@ZZu&`EE)ym8_jIc0lJ#dX&jZjgvEj^5Gk^&tJGef+yre88F@~ zCJ1EzIRBLyO*19IPxp@f3r}>~k5V^Ye|+)c#j4g=^qXV9nwpx3{bOezvRdByGBUIL ze*aE{f+P_~O44$yqVL zS^1J)8UOO+hW{=`h{|-!;?sLSwOMdMAXM0%;eKNV(5^ESv0 z1~}LyV*cloKdl;Jqyq)kMh0j1=59Bh9O;=GF?8!GoAq{Tx=}3S&p)M~X?kgP`qvI5 z3yygtPBYS>XS1)Yu}`^Jjv93pDjVUcwXm7^0k!|`496<9-?!z%YxS`a{}YkDs%NCm zd5z@1-b_dRNKw-l*?8C|eagC#H@2eUV^-v>4?ti&HG z?AROFsid#r5fPSAJAm z!au2NdR`iiF-cYb3C}r9hY0u29k^3l9bt|@eNEoz(S3XW^V}IB=l#L`cwl<}?Q$;v z0gi2_Ncf$yW#&g|m%8Dv%+_7hcr|Yv3qJtG9<-->3pqMKv`@)5QE*lv@VjB0ZXL)&4j!#5*cG z3ae&tv?dG&UfkX`UEtAkvgeOyfV+C~Bf`HV1<>AMMGX(Z&jJtW&IDD1Z;@VHLik8!FUeAHcnDLH~yvu>%CZqb^gwRY<83mPk zBirjH{~hOzt%%xPC9prQvCk+p7->d)!|vd>j;zva@cO*VZqAAx7Ks3$MBqJHiq zIfpHQ&<^-}5dZz3umTRYgi+kldC6DQ;H)xDAIpf0)j7gcdwYAw z4B?MBmN3(QA^IG7xgMC_Vgs#=^>C7thm zhc-m?vy&{|O~3m^?(X4n(k*F^OG9r#liZ9CWj3+Be!yQq@qbPtD+&T71anmJ=XjOg z?jkeLWTb`MgPdYg2iyDcdMp?Rtb&d{hYlSwOlc`vZ(s+LwCmNg^ONNG21Sqv zI|`&b>u4~Ne6&g+XR2&K{DcJgfQ;8fWuly3;{}Jj?-*Xneu|s=xCrkg0KZ1gh&%a# z=Fzv0PpvE2&Q4XV9l^%Qmi_L14KBbNI&d#1(<%Izg}%66$d@yWabC{J-`?jK4dI6o zboCqF+8n4qDvxOYS^00i`KJ>O!GV2(Jx7Tjb@}fdh479iw3HCGKrPM8uHD7=HGbA( zA$ir3i+}}G{l3Ttnp@wR{o-`1Iq`N95!IrXYj?fn_7>wk;83U#zVQ@TfL-(@Kef}q zpg*Ew6KNf6F~Ya`JZk;a@pv&c0ZoJ?)<+wh!$W@i3`)9|{7>R=uJ!;$S=O+kVVh7Y z@{j-QbSfvbA6EpyL4a>5b%b>vukN~&2eTs~(p%`|WK;RS(+7wf79(2ey>~xrss&7^ z#}F)=Cs%#XI&#(3kbA1X`s9-?+B?hTxyhSXxuf>l8h^L9kA6IAh7#cFh2`%kN~@~B z-yQ{_Rv~|OhEcJ9xd7dsg#Y3IEc@dMY!M3-(;CezrS7+_Eq{aKRb~he+9lGP)olYI zgFEO-`DcI6{P3I`fUW#P1#rDWci=x@1UIrJy#L<`1@CJ_#Lh!aiJsr9`N}15_F&`= z`(fQ4(wR-jPP2otO(xQYwrgpumER(SRDZ_7bn+XJ#=9m2c2g?zUXApHLLsTcTCd?r zoXW;PaJ^v~Jfj8)PbPq=p z2EL=ij35J|FBX7cM-;m>4e=eyq1@iW|78V`CmBO^h_-q2O;wiR2~zFx$M@#b`AkTh zvP0=7%K$WsbU`6J-Wz`Oq;v*13neMk8Z&SNJd8jMoW)}gr=QA#B?b>t z#S$9<$Oe9skdWw&)R&zEwb876e&W^~2*>~40O-{UpBX(Sbl;wJAKlK9`^?)@KDBTD zGm4BER*&D#?Z@tu{)3Mj0jf#7-J9!O?0uyj!AoE>INut)T$cyo_bNUEG_D$mu{voC z)7o=t+GC!Wk3EUI?huxd5m4u#l5}rY;m2=4&H3r^zk(Jhi+1nOm}(jF28r<`>8V(P zlN%M|1;!@070>^kPQNF(xwpUe+T#NEx5pBlvGlfNN2{0ZJDO#}*bI`;uT>|1f2aqM z?r+mkVB8yvU$8v?syRwcgwuZx{1OcaZIK)Leg*_DM<=W6z#unWRoxc6ah@AYO1xeJ zHq14)sBa}Y*o$asdo)h`{932V5NY0lgDrL z@$B=!I{e9SDe6qaghTO(UY=V=cVf$4(W4_!1T^Ol4RB~$-G{c|+bENZea|lUtR%mq zocO7JY_bhqAwU1mFU&ztIcO_CIkI**K-S}LK_6}&XwoF`R?kMb^gl}mVpkCTzkO;J zS7SlQ)H21D6vciT4(j*ht@+8-U>&@hB)puV2qXJHcMfiF0?G|=x4}+j%RRJjdtbZ8hq(NH_MPnZ!1|j z-j?76tX?~;7tD-)oy+=>GmNd?PbUSUq87xhN`5Bl3(PSF!U4{LyhS}!u#wcg4^=DUp zfv%3Pvt9)Kwosv8M^vy5l1L*4-(zirzT9rE4ow09w4$KlhJrnHHjgzFb_crIhzV*P&-7dfkpa(_lZN3 zKNsz$Dr-snsM6rP?|)ba=qpfKv@U|i%7Z$@(LwFFQ2iV5_8CwAJAMB|2(O-g?s)PI zG8d~h(mC4RQO|W?u`AvqhU?#e_sDn!Wm9(psrH?APishQoT%!yg7sq>b}=t6uh=eo z(aG@*r^a{S62`gw`DO6O= z#Dq_qi|mv7QF1~F0)H3*bR24l|GdO{00tSaLDm@qk5dIw-;MC2$K1OL-0qTQRR$wA zRsYd2_}9URClbH=*JuQ&A@_t>25uZw7>EMrC;33#06G*%0Lb&s1|N$7NX6c~*(9_e z=>?bsC#G6&jUtpyR|#z0xnbjjoL??~+CeLJzf`rme8|Cr~l4!k^vBP zgb?HtRN$HZ_?U!#x~RkkEN2dV4af_)=8k?gGc=TZ{Qt`CBrgFUYpP^2OGLvM${W}X z-Lm=Fud9#aPMwtXkKpdY4*t3836f9%T4-pEOY@*H(T*}8b>S!s46^1S>a#6uLzW61HH8Qm{<#4pOxf-adb2N~a`01uL{Al{ z@F>4)GHJEyDpq6=g`Fo}IIyM>ic>oh+zOUXH*0$20w8B8P( z65BQOLkT`C`;|}h;1V~$HEHxsho9EbAA(IpIOtD0s(5R%0p17*q0t_olF*O#euhXv zR8*9vsCZ44CE-gRQjNe5X)TRP?riAs(1F2S5^3UcwpRbBcs^-axdl60xE)bqrKWK> zDh(uR$LHLJ3O>PB&ouhedxZ8DZ(~oQzswlwgRVhQFMYIDE*cOoxyQ3+S2yHcRwE(- zI=tv`?y32?KTB(mKq=Y8bJ6BQB*xApttwYlpHTu|%Ze6LFTDBSR*WRxM&~qUD=arX zOouJs5n++Bk13bS#6@bnSWhPtRisU*W;lZ!;m;c+4L$?=(#Pzpwb1(+h|rV4Pgq3T z>q62z%!wyM`92_-hx=M7BPM+4s*jc-hT2toMx~AH-#RxG6Nc&_gf_ekV{OkbMgggy z4T9S(he*wIRE0`#Id*IleG`PwkQO1enQxV^2b*Z{=z6RWv<&>o{7Zq^u5{Ymvy3r! z6<7YM!J-%CKg_gBy0?1_i_Ztlb(b4%VKZ8ZpY~O`Q*?uU`{Ic@0!cpq`0-{ppr`lr~&O*{j|~z09!vd)}u|Yj59$`e(;V z%nV+oTo~w+Q0;j>yY8JvS*oylA(MLHM_1oduIMHC`KFg4n?!T#K`yZ?et2VHwYclq zy6*1oo#`~2AMm_HrWULY$gc~!+uMtw(C76`_!|8iA$5{2H(lwfcNZ|sm)st)w?o`= zzwVy5bCYc=wz}heshRKH#f^8q-58!LGVv+cw^?sjP&ne~BF(oO_ylt-_CHz?)JOxO zq%<}MiNhY!`99P0;rLS7=cG6gKK)5FQqW5EHK%y4*PT-5R(`>|GjrNpO687-WkL6e4?C_UP!9;bv1C** ze4U44#M$wmNmk*o{xt*)69mGkvMQbSVQ*%}-aWRA4knP|Z+F?AIXL@t%TIK-YBUQ4 z$K0t>yFAVteN%(|e9ZL(uJ2omH}c74rMPXcD)}lDtB3>A@&^ z?d=74WM81{PB=I-B_n$^Hv;tMU-ffUtFU5V=P#DBsxM`d2QTy8Qjh(+|Acnm14Fl) z5d%_1ue+U1T(l}LN2C?avOz~ogPE1Pv%Tel$BRg+^%CyQRVI_R@xLxwJi)6%Q; z{gvbI(_9dubk38Wjq60YRECRoU6pep1#|@zWq?sh%Pjjm`Ime}R7}S2JdNo*jZ)Hy ziELy2ic2AW8isa$my?}ujMEP4aRHo6m(6!wxbY?TCM&Hg6w!j+#w|)pw zi8R@?oQqZYut@7!@e=EzX>)VcmHC^==`V4gy$xaeLc&>rDt`q?@smFsI1mTGA!io_#Pzr*T#%X?*Glable$r7VOH}kyw zl&`;T{5f%)+j>3F;`C3u%y*sLAQar#*DP?9S{6+;)*Q7( zuP%m6wi}%BT_e4(Ks9sbql2?qY0K!EM?Kf_zW1I@Phhcb#lcz9S{l%?B3+sx$wLYs ztN=0@J)n4DwaW^E)cXcFo}}Nc8sp-$=_cZ9XOr#ZdOa0@A}P+nqQ&0 zUosu{$$evd_<%yIk3{xulvoUX_f=*^T_=q{j7GMMvyd41L&BPfLrwJ#qE4w_*Ux0W zn$_~T^EAlS^i|`ow5V0#d}|b)^3oagK9L?bUMs!3H%;OVq#AcrZPog+6pGBeb%+&E z2?YhPR*0EjvrfOMZ-TS~BP3_2sJ~Y|WO(aFuH${x>j4uj!nJCI?ShRo4XCX@1|{kFU*&VJ=O2L-LLF8RsITN$ER`1EAd!up z>G#VL^HvoI>FHDa3sD0`MSBwgwo)kZy>#P_jP*dGftgpOEBu%o!der0s+c~j{JA&G25_?r9je+&Zh zJIn%L>#qo2@aIY~e~SZ@`W#|eS)~28%;-``>4y>nels=$$>Pz61Hn-*O{5>#@;4?f zq9n7Tx$_98mvN%_PhOJ)g~o1U$smNZCx;15%VFLj8G@48fNq@rknXbyYUz?}qcAG}Kp&9$+}?ux_2>WuJWw zyW;E4A`ILb8e4!xZ-uiWX(ugcGeA#}S2vSnf5&ZM6x+*=Opg>=CEzffGr1H3alJ!p zdFr4~D-Ht|XA-}p^*U7{LF#JgfcV?A^f$W}VL1}XRTEGBr_8Fe`cNT@fpnne?L^h+ zPZvg zpB>Uwma^h|acAwGtVx?kLJuo;a=y*7U-DgIv~u-z+rBSKotb-X*nVV*d7b*|rP2|h ztnFXiw-H1eIEIL5R1tAsa;6vrz8!$R&9-LPcm zt<2N$KZ;NJ{5m9dRw+JibZF*i`Mq@eXDTNe8g#syh62iZ?%X>0C=lvO32s9aCAQVn z>1$m>XZQkZMcj_q72%=LZSB?uTVJ`0fV8K097^W*MkFbT3?s?xuiS!THG&>1LB}k6 z>jzeMZuqaQwji44 z${ja{kf!F6-zVT<^NAjR^75(Lre~b}4%!)<`JSse0py#@r|D#Ux>$tb0xHO?)-ex# z4MwGwg+j~~%LT*3WMb+IQiRjNKwUlimMBA%KO-Np)@5=(!2I`8sESTjLpTyCirSjM^w)gWDHNu6A|IW0^k}Z52T%Kiq^E|3$avm zlE0U)=?|mbWT|%8`GsP@q+%24`HvpiIt#aZTHw`@!Nf_;ooJ=xEv`nkA0Ywkp&|a^bmv7 zphN^=j_w*JkviXl*d6Rqm+=+O2jJFv(=BG{$V#9=r^8r=%O3H@RrF&+c;uyJ19cZC z7ct>Y#9(cY2=avRKl6n2Xd6ssqodoiEnX9aZe2h9a+H}VPD9?fAZ9pa{>&B29w$9f zI7Feg_QcIVc$4;HStmzF*Bx7)szIgn)K60S>v_|Ju_+S9_KZB}Jqcq_#X?cCjUSaA z@9xPJV%ABtkbRb=AGRdLj)7XFb#;*e#VnD1jw~moESu2i;_kjH(^S9MqRDTi@UnaD zYah$fc7;VSQ(`N&OUP^EHI~cQsPM+%9S+#Jxae)+{M+(DR|KQj_2EZsr!{fDyB}3` z$ZuLsUEw}_so~;)w5BZdLwe$G@t-gHY%>^*Xb!Yc8?{Fhvn@B2M&G&8qe z46!84Hi@pkQCijU15LPpHoqb=qlq^zYeZht0xKW$oPRg1#z(yIVlNJ|wFt15hYug7 z9xIi7W|Pl;M9Sjz-oh>i3u%c#sKLda`qv&*Yq_`>!EzK_*IQG&qpr?SZd`0HGXRE&C zr^TSmGyHso1n;HoV5A=ru-+<~72sq*fI8|&XKJ5J6l z_qmo_9f6DbS}j8U-QW5CySCi64_CuzEVLG6mM}ToSkz(eX~K&_XU?nTacL&Cek6+?vHEnd<4Ygm?6YB=N3Pc&4z&IQWw8G&ZP`E4`l3I;k*_?qUIpVpcrmU8;pFq^}=D#Q3h1P_j|bwzEYgJ#&9% zx~uYGRqi8O{%ku&XHD-V=T7Hta%$QKRS)47Jj$$wf1io)T}O;%r6^llB}9uVYG6KnmOW2KH5n}JxCz^q%q`9YGJU^Va z#ExCm{)!53tWMMik-jXk2ziilto7~l%;88}oSk*SkmAZK5<9nb%grHY2Z!z0zWDg~ zT%koBA#)HMJ-+n}UmCW1zoQs)rGFo>QzBgF3uO;P4puoE;jO}I+uEYg^{@-8g7+~A z^=CSoxAk_CcFJw{!u#M=N7p+zD5#|imz^AWeR8CHrcz_3l9e1G%0p_Ma}$4Sud+mB zuT>`p<@)NIedwBt`uJA{FYr`Yp0=;QP^*C|Q2%rpW~aICIKzxLjn>obD6A(|Fk5zalbp7klA$N-E zz1S5SvYySLimi}bO3pQtCoJ(#{(d*#wv4aSIN+G<=ckrY`SE<(@T0n+aa^ElFCP!a z9~KLhJBGgx$KONhvx?=<-#ZOO#E<+qcK@6sClhZx*M~==pLgV#JrrWizFiI^jt^|| zue0|?gt6cC@SZu_f%a3v8v#Z08 z*7CCPUaxquMq?5+A|#3zT*;0daQ6}PzLmPEkjCZ98yliz7k2+iW_`w6G5ouVqYinU zdG3dPP6sk?IbwRdR;IDh{DA3lHfD!BHAm`j;J`YofL;K;>_{J}T4m9@N+sc+x;Pe; zU~0G4by~XYT}Oo3c-w6f*Nk(_)P_yp|J`PB;Luc=hn&3@4AC;Sb9tL3*99*=4)Q|z z%wv-{0LU12IW9WAt^HSM8@qSz?*Xqf(x}^jxW@ zXT7)-g`j8X!H*xV`V9N_a;=<{e9fLp`3ctx4BB|;q8k1kXAZ{fzMewer5#&Qv?45H z0VO;oyT?5%zo_VM%)@Lyb*fBbXv4VE{NE=mhP!X=kiE`TaeWvfp}so|q2_7RwS^LE z{wV*_@!LCw*x0bt!Eefr;_Q{tmuC5bJX0#p`qsprW)Zd9II<|C@(o|$P}zj)uj-_5 zLAI2)7Kbwf-g**nbVg1?p-v`9As7dJ+d^*YWR;RywT8 z%E_EE<~g$9$(t7EPFJ-}b1nF`SKbL2S*Y_ep{6TSh)~vGmnMjYO(|hiix!-rV#B<5 zx+np1!eiyI~p@-*TqrKy+eCYjnz1?}?-*m1vBjjyRJ(wK?a!&eRen?*8sy>?!`7 zo|`z;rG}2rA93&8D3DqHQ@yILj!o3W6J|Po@)ACx36rhiVQU(w zQWm_zFP441<(t5x6PuhmdL%W&LzVp{oHkGOb2G8p;_c!aq(;^*zcdt>je$cJGKxD^ ztL?#~g~R8j9?Vb8&%L;?+2Ss# zx^CKawl5{+X*5%9c0{g1U{h(%#+RRb`lmOyCUb7s z9eMhLj=ALxn+&|5DK1v(`J*~pwK9d~KR=S)ux@t*EAg6QjYQBZjmYO{tm9a=z_cjq z@zj&gD>8gXRWU!a@YrteiFKUD=DLe(Vvj#1cWR55v9+x$(x}wjk(CwuQ<5XQqRk$R zs~cqm#=gG}(kPYunQocc>-BfJF!H=tX)-@2ej(LUDz`HuxATknx+B^b?(O)x+SD}m zO{k8ufL*sd`?`WN!f}%FIRodXWdpwlon2^l!0b_0z3vXz{mKb@i!Drx)l_cf_{CIz zgnOm3M=%&k#jkzuJ_oV4uBwZ#?BTu6U)XZ{bIayN)U@0EmqKgNYm;W=o>f^_)}6EI zKmu56`&9m6BEuqunZ`OkQ9GO3Lt^XV7 zzs%|2>%EWP76>h%I5jTqvkVxxd~1_0*1E$sYZ&2|v6%?B_Se-YQSu~PAFw*Z-C8Kb zRJ$cOR7SDezw=?@f=`Oaj=cZCU|hXm`!Qqdn#G_;2>-R5WMv-cP9Ceo1=P*<%WZwr za#OPn1AXw?Wnb@ijl79C>+?v1z4H7Brw)tub6b6+_t%sjIhe1FK6+GBIzwnu;aC#C z`krr^I0r#8(7bjHZrSn)2#x)kDs72tEp2UWpC9M86m=TkUS#k*gO*-lY2eE2Zf(1} z!#`A4ikA&=IsWO+)k=osc-|^Wy61noyqCqX!K1c$qA=fqh$9N48COMb-J7uiSmgn?|08?hrHocaw^$-hJ{hT`kGK0pV(pZ*mEf ztg&ni22z-$nS4l6;+DHsd*jFG2WaEpKPTZJQ6naI_i&hJrF=g#pE4MWf(lqV&H?d) zj=!^|qxI_Se~)dQ3ae?<>u$mYs(1v!>0vGBMeJePjmim)?PuCDil6Y?i%r(Vy6~UB zIU*kd-(;a+XK>J@(T_unHBJ1;$)R^mYA1fnKUTzIWiKBPKf)Dtz2aOrhejxkQ+3AeU zIfIY!9t5#rpMrNv>aS)0 zWou&Fn|!jtkJ7qDOBa^HN-0-(uH3tJ8M6MgG;u^4SfK;b$eT+jGM3H(o%0k41`iQAwhM>3~H-=kxA*;QHJ zpO%#O+=4*+OhSy(t|GA%))2(RC}u0qPUel`t^lGcA&|AMl=YRYI z0x)(U1laT7H9!_j*}dac+;B|5nh}WuDvTtv6kdom8BmEBF$=ksA$F=mo$^3Q!K0Rc z_tmyn)-AF}jE9Z~QPxZU*AE<b> zzy-=8qIcE52nUTPS5yV8u=^YtU*Ijg3R7foUzc)fo;7xaE3V=j5PvBhQ-8PR&>@88 z|7I`L5Pzu$W@i1HAN{pCzEYO)C=Z)KNhosVJ$Z=>TKq=c^!*H|?_1&!0dcN=>;CJq zq})~Q!yX5k8XDw9mWKo*_(K+hT?x3k=C!Zej;(5K=M$NZ04C2+s8Okjy)HI*vR9@! zYhCkrk=r7%s>!;Bt-Q*m~>Bq>`w9{ayi~ru!y$B^NU0ce(i;U|h6*ts>v@<-nxc z4=M3a3H6`OrDav>;9?fr55Qn30E{}N3u(b;0nVW`SK?H0%s_Wcibg{V`wBZY zfvA`pAFIrfo$WX-F&0p!74-1AV_tk*Tnlo~)51pi`v?9aiI2h*ku<%PRH7viR#PR5 z6xvKcr^rAeZ|dglb{CrEau4wbTS9A(${Sgy3k`@jt%<2mTrY85ok#Q0z<2;srmW5O zd)6-NB7M1$_f8>N8J#7)hgYz;MiG5~@6S|_Sgw-;gbSa?yrn{w<;GHR2{B{q^f&Qi zkrzaC1ilnb1X}6q>)$xRbi@)h9(>IGX@!k6Y*V(wauiU09cy$P=jz%LAdR@NRPIX~+d+Zp~dt3NA@L%@z$Qjw&9@=AT>dG1{#2YK6 zG;`hq*w{4oPxJsqcW#-cB!55A<1_=4Ss{KDZMWt2VdjM9cfrkxp}^#}k(rEa+!&L! z`k#y&nV?MbxQgTwXCqq-7;Oz@RCJJ(`z!IF1+HX;DZ(13@K_n%*a=+uZ>B^T{$vmC z%+FiVRiP$gHHXw2pFU-*77tpoE~b9}{{6|%s}_novSA5BkR#O9w|T9^2&{^#Fzp8H z9}W`Ci*^O}BjY>$SQ3e25h)MV#o5cWtHp<%DOd4}1{qsI;}r0HHeuhz+Fgf&gaFRD zBE=%BFKTV^I-m5KSESD&`aD3YSigc;>{^1%Qi_=57xBjNyKp?_NTrw^+1Sf($8}!a zdYE7~L$=gUB)8aTU}}5s?{#+|c&GUZlq-hUCp7NR3J8tG1FRQpmk^7_Is`K+evp)F z4Hb-`k_m{2wEaLFV!HJwznxjF=8Y=fsc|wjCu~Hz!m;0LBN~5@3!56-r?0~I8(B;6 z4>(K#R1FcO|5EDkuW7>)jLCXDi12)MK_YX<-+v%6pmhXd^`sCYCvN3rf}JQa)LE_9 za297qvaa4|MY!ATA|_6!lml_V7XgtQNp_Il@NDy00`M?A^Blbvg;c6zAsuif@Sj)Q zzMWL^nrpQXY`EJsVq%}ZRNV2jv9$!}fWtAo?9ZK)&J6>J6tCh8Jjgi zgsEYr2z-c=EkXPak=T`hnQr<3NOraRL z`cMF{)Gx(ML5rW;E3BnonMhO~&~8Za{JKC1{7NZe@cl#mP`IU_rm&{`WVw&ZR_b<;+ke+qXhVb|IVCZv)XtC zIPG%`x)ukwx$?4|Yu7c*_?zL1Y07LYaHP;(wcA5ic=N{6wgJv54e#JC8K>Tb-zq$N~=Vq05QVRkx*x-Am9&-HoXATwEqiioJ=JfbR_f|Vv{lH ztggO)#mEh7z=L7?5VJpid;RP5AE1&7`u%A&L?Y(ufdp0B+DqGt#MIZK+S1ra`?QFX z6}i<66tI3=&Ge<1VJ88F8Dq{fDr#dl9VR%RG%ccHGi-B;Hd$U*$Cb8DDfom3GP{9!{| z#>mPJwN)aN@Uf=1*J?4}gyP>{0^QJGgsoYaT7m~v|F_Nq<0onvD@-MqUt&A0*}k@Q z2hUk)>lY)M>1B%X>~e4R9V>NLWh*#u7`noZ zHB}tY{MScm@5>sohq^gSEgzAUszv~3;)VlsU!ouw6b2PamObG75C7=9j zgY%d2s4I?#FBu?|e75EE7qHmS_Wxkkg*?=6ITcdegpn4LG~!zJ6bP}HEyW^gmO#=4 z-ek;DxU8-w76~Q4ybb@GrYpxPO>bSe6YF^p^tVeWLmjb9+_l4ozpVGsXmmlIbs!ND zoGkNDtvNSA#zud|INyq>)Z`I)ic@qJf^g3BAVobs@ zcxKl5`_UTqZOwim4^t{0HvEH7$?i;P0c$O61n92y;_9S|l^bUWt>PT;hm(aJi5wK4 zw|qjQ>@76KZvK8;!uF}}K_ppO`jk#kb@g_7j)S7J?At^e{sPwvI*QuQ_uGfv4H;7~ z#U7s)PQuI?N_i(pW^TWJytbM@n|h|8lG4=r!2tn-a$5QkG#p$YAp`UyV9)`#UEu^e zjEtL<%}(nNA<8Y-mbzktyv&M|ALMZEe_;B+nA+v5IY3GFgt=P-Ej%@Ul3)bOatwti zvAaEAf8Fv~IV5Decd>1i=SsvA%PtvgWC=>$bo5&i3J~c+BFD}VkNBt2BMeJOqXlw z$wbst6W0_v-Zu2K>x}{gbvO`=q1v#9{nS+%)8aw>{TD zCKEghr;XB&zphYMFlF5^MfwHK(j+=SM9(<-N;?eO-t!A=M;Il_zzl$LUT4%$KtYQ2 zYEgL#rA^NX@nByk5!hN9P9roT4GG)|PRcbOb4j$669T=U zOj0gdQ!V1icJB0PVQYJ7D%Ao`gp-NXs8Xy09Z?^|bF0qU98%r3mf!APq@&wV#kq|U zn6q5H4Vy3J11d@VufQ%^jZIHoUEMFmxQ0O643VJUszuQHu^S&BUmX(#D5z);3LK4& zt$tAYIy*5P7_FCm$hQ_=(va|DQ%_%r~CAwGx#4Y*z^M#m)`_L?e!^FTm7>i?N`{Zyx&hKQ| z1J~bSvw@B<>4A!a@&V|dGt%W`2Gqzy@G9G%a{lG`R&$5 z7QNy#&Kd?fQ&Wg{y+O;zw#%)sdsHcshqD&crgFbX4UI?Jl8dy${+t^;ui`owUt?;` ze(V;pPGM3V99Oj@*td19;CA?Z?(-$qEFDBJH-d1!hJ61$U&+1iA%1t6jGkG|w~mVn z+hJwW2mZ~>Gqk&D$lkntl`6IXgW=MGRseL+w?W+Wkhm4LCJ*CC!SjFJN|LEs(ja3W z=BdXqqW2e=wW;oGJTcDJI9w+lM)4_i^h2%RvwdQ$_Jyt+hu*ac%U)5lNMDbGxv^s#+%5 z3%nQe+v!CPx(-!z;v@EFUe7h>_yL=B$&PhU{1a5kG$z}28_r%7tFfR|ZdIemre2EP zxWnRmwVXqlV2hm%De5qkYE}i@bW&w`mmw$hY;!|nAIqQwxn>2P{fOfx%P?>cT_LNg z(U~0xC<&rSLuu8pnNc(LBlm{5gPpG%yku$OSGP5-(#UTnHwFiF)GF@2xJIW zNf=wZpQhEcB$f2rNN>eAfTqUZ1LQ>hBuHqJFx6|xTqz!u`QM1bi1AYEINm{9bhUEL zA+!}+aTn%YHOjch0NPNoMS4|Odhd}DVdY@1+yv{e?^WB(Q;}F9lj@=YG-Ic2_0yja z55R!c$-&IRcT)+rJJhcDsO!E1!u|U)h8EAe>4sHoNk(}N{skBb*#njO-ri)3*X?y| zyY)o}o8;Mx!;80cS9A*luZW7d`tp#HBsPKiQl}G7Mxf4B@aK6!6ZVwZ%PoLlbmE&J zF0dJ?dKj%82X?*;;K~t{eYbD|J)}gWZZ*S-Zj3;T-!!;_7_ur{Fc$V-mR_?Pwt{Z( zj~Ay@>|8*uBIUPV@|Md(O3PBuAY%HqBb@g3!^!%1v%9BxC3)G#0&neIPX*}+M#rAp z`oxd-#*@trJFU-t5f>OOoe=lzmlaWK-d)__01uJ9G3<)a<1(?YoldvZbFuwaT&)H{ zMP?S3mUCNk%-V1T=2MO?*RI0~;-1Kr^j=(tY#z|Wj`E%u!u_eh^K<0bEANePdTt92 z2<?Ih`3&Z&Leg9Z9RS=Dz__2m?}$SX8Hvf=wvZJoW~%UZNbjf#f1t| zy3}JJdF&V?N%cl>D|$^udfD)2b#QR=eW|cm^V3qBl~iUmZSBPxp$svuUlaQjyIkai z35puJpF22MQgsYpmOcJjHeFd0`<^t{&;GkTwuo1P#E^gz;#`_Zju7*LFO?-)-FU8@ zf$*yL8N>%seNUG(=xj7w8$IWRrbiduWi;F69WH^onHbhKC+C5gNoCDJ>k*kCHgx}Px1z~Aq4R&`1Cv*5ZM|c_%kqZcEVrJHKHi6m zc`$(Aj?vSkOW>I&Oz&90W&jk{UVvyatE3fxM6X0$A z1rDJ{JHvEYl*91~L5lds5A>4nHmxPhgBuB@Ykk+om#BN;_G}G~TYE{MyXk~yC=95v3G)=s zcN@}KM;6SQhuP8P$9l8XA6BEuIUlnehW9V2Lr<5j$#U_@QcEaGe10%@FJhJYlt-0} zzBT6kUIbo6(g!VW@pRurdG>={eh(pK1Xf>kMKTi&So2%ET@R@WyUKRwU*aVx~!4Msg7A`jT_Tw^y9NSy!E` zSg_P0ZA<4K&I_w^HVZ9btDo1kS=6xw|7FEg2}VZQhmnPByb{-3Fbz95{;>I9-H#) zqMr(82a)C1-xlgDlwyCu#L8M>(<|BLao`!`rcy~2RgM|gP0^|nFakxQ@i`54@U~m>An_sJ?z}AzP%E?TJG-!rb4oM4ko_dCF?1p<#KlqJzU0lNw7k%ne1b z_{rz#x~!t79iX>puKY0_2&a^pk%1M^4vXAdx7a}Y8Bw)RQrzYNQ;>}2P@Wg9@giTK zsI%`KCcStZGCE}9`sVeuw)Xeqt${>-BSZHJ{ip9Tpm;(IvBWO5N;gxCBYe0AbT z(lQ;+Klg4@Y2Fm$w_mBA_??Y%(+IzF)MvcAGw=K&)r6*Xn#+}|hG;>($&4wj>>wots^*)$<9h@2sD1jIH1wx0umEV=0 zY1W<>^iEDb`;Aoq$$d& z%C#5EY3xXz;pU}eLl}7$75*Fw8vV9yXl@z`PU`Hf4(+@`HT4GEM5;Q%uNfa+^YB5tdh`5< zN&orPLvuYUNla!K#Ce%c*S)Ikf8M4eSIG9I$v$fVl;~XGC>Bkx3Ca;D4g2!BVO#J# z`6WLzr2A(CaDBWv-gEpu~sWEq$%bO{<0{*j9q{B9o>mvO|{-U>t+byM;FYt zO?^xjViys{Ww%o20dY`4ooXPbaqDa*~hQV z$62k}|BWoQ-%OC4-Jo6M<(_4+;P!|)#_r<8o9z@F@%qf6LBAk%*bnJbkof6HSL|!? zsx04Jw?X*zXxe@u?_Wd%E1EQuj2>PLON`)Y z98Nyz;wn#4Eadano0B=;@;t6ZrfHsb;`z}FO;Pc@32?@&&?D+i+q2f$-Mz_=U6|ul znfJ%0=4QD&6NzVh22GulwiHi}oMB!1IX%JsO}gS&p`)kREvnEgBe49^b{?iD)$_Kl zXiM!VP6S!$sh1KbmzaE}##^>ywABLg$`XVke(w}3< z-?Ua$UA=S$`9QeD_Tpao_1`2)Ee-MK>(m4-wY(;+ceYoH z+VH=^x}1H;8!MyRKuhEVQsZ6-Ywh~!FjfZg(B;bN>Wxbau5CD0^zDEA(UQ%qyz%ra zM+JR^NhjSIyX{x|o12@<306_~sbR^MGAW5WqEa1@>^L<)7E_*qRM?|xh?4UA z_I?Xe>@M2NRJpsH=WSm5UGdaE5$p`_+LFF=p{T_b6CvF>0EF{DpRlej(L1wx|3S}T z)wRb2uGbxAYm7XaO&#IDa4RbLvhRAG+uPyUL@S@Z6gqk2vBD3@ zF-O6oP(gn~m;~S|PJ7?0n6~{0<7?3AJq0=BH14x8WFgT1Yh;F^+{G4Q-CW7L zKZ=_JM?F>_eIGo(4RjF`Xtra0!F@neMV`1N1_oSlrk5kc`iz+P`VANP)amBjYt_%G$~SdbCd>26B-H4r3lq~ zoaK4;_xJg{`>(zCqwBt|^IYSxj^3c_>i&-e~e~b=YxOn(R&xik_ts93Oo=hwpmxr_FO>XK#c@Xr2 zGS3@X-jZA;&juEDU+-beT;cG_Gi2?(f6c{_PbA#-nahH_0^7I0NtM4(Cdc$1_3rdf z2;I+PBNb{tb=E9++m`XuA3VV`S15h9RI>WExs|wsWN_4JNjU?;4)j&JlBHev$tBXVZVbpF)~#1wV_7W| zY6LYznY=9uff!bqzj@1l%|0+Yo^`#fnK~x9rU$;^?e#hqZOmh~GVlrB@BZOOts!BH z1456Z=91(WROd=*JixLwr zLQ_4$K9uj!=tL!9x+m~z++}lM0jrv9;V*9egM|zpt*W7njTlkm< z2V3S{gd++YcE1mu0 zC5OT#{p{F#G9of^riWx^I~4QSj@)rCnZN$ej+BOa zwT~kqGtvdg3zvi6yefw`1E1H(T*Jl_JlA6y&3v}zR3+592A`yC1CKNGtyYy>YL1q8`cN# z#j7@7cKhO_U^(#+Ng183R8q0DbQTx*q&;knbk3s0Gw{)kEXD>tEy=4QDdIfK*$~%# zoqxf5S|nv+I@yJrfo<@Vi(cwUztHf$RIt zf8D+(@LYTze)ZmA0vZ$#_blJab2}MC-lnNYk_9uTEI-#{o(jz12!Q{4EzYeW46(JX zC2vxbH}MB^8x|hYTed}qOjWe~r`|e$4OdCpz``TTc<@Qd5G+-g{D`$)I!G2D?InG>&q!oVUa|d?9O!bn)(BOuq z?xh-7>2Pe)+m9I`8=|-Lg|FwJm)?|6aOakrhZxYf1H)^-XXWufvuwcFB2Gm@Dt?M84Y4L?T#P z$-*?fY2Piw4&zh#r!53NI|nphZC;GXB{peAl_GEOi^#{$YgbPwcLl6U+6V8hVW5SL z1^uU3EJMh9#ES7HnAh7^e0mL#`1Amog5~CET^unh=BweBJbnaN2((4=xXCFTK_#_U zcQuN1edDSu>_QuXiQ8ic_H)UdLfY3iqND!!Kx_7uA$IZ40&B2GLr~A>{0ja^ddn}Q z79Yap^M}tXkrKrLA*p_h*96lb$4b)JY_A+wiP6!M!8Wrlog~akD7DCp#tZW`#v~-n z6k?a@sRU^U+Smqfn7zV$n7to?;bGdTDEd&Lp0n9sHn$XVzaI(tpCXQUbd|F2T-x#a zm)4lF)>tVvaV3uu}Ha~DSyNUN47qp{M{^PMMG z()Jm&T@`|!Vg6y_#ptUwGsF9^5_UmQz%lV0@@2Yfq%@1pUm&RHQ?hV(n2W{49<2qtMnphlYniSL&B_|yzrm2%3(5j&^fT{Rh1(6sJ}k6Pkj(;sX6BX=`ui# zcqN(bs|NPyJEzasMeZXV^ICJ2LjvlLDpKJu?ZNV!Yn*h$Ds_R{F_iV#zmjPzV(ZFt zu_@F`6vV#AqAhc1Z7c%y_wo+)p5l^bnh99A^i*W|OQq}IAo)7|#~_@~EImFpqgLyq zd0dV4db&G8km)^`f6g!Uc*6^1W`D@&R?kS)_e`ZriL^Nw-rtWVIhP9U(eZe{>B$Np zYdP)wwL9pxB0lIFEhyuc)+@$b%3~~>%+pqRK zYUSS;kQK6OWFdp|-5OLDW)fnK7fgDUGO;W?0*~J4cp$#FC4>>BimFd1FoDV1L#78yhpVR!{7wo}gov5D>QASytiZj2=Am2DE*CT2X%24DLr@dOBOWb1E;^Qa|zggpWzn z-TYEjVNX*pQXu!dB4$Y)Nfxfi!y>G>!j<=}&_5gu1_u&AbR*5Sx1udJy7$!W{L;m< zg0Miq>O_fYB-q3~Hl$SHbhVzS>%H9IAldI=-i=kDm2yB}$HAu}<}WPWn8Mp4yE|1w zK;}`Y(mL!MJx%sFwmtpe*>)W5rGeLLo`Tpva~hn&p~VY+Xs2o*`$kOPCApds=l&N6 z*3Rfhb+cV;F^F@w%w!h-_+3!Tui|{a?RcSS!BAUB*#0NE{(_Upv-U-T{JK0yK;(+7 z%F++TTbLK>s~b}6^?lC?ZuuaBY%uPV=NV6_WpmCAj| z!sv-em!-sCr!XS)F~Z&S(12$fWRmH*+&OPS4MU$-o(riM_n*TSaB3j5kdlWt->eM` z43sT8=OC`BsvazxeY{;0|Da9r`s&fA3U|(Oq@iT{1Q~zMa&f_p;C5K1MwYIV*Ipe_R@W)o@_u>lD)$17+=|ng?0fLLOe6sV-soWnJ^$usn`LpLTo%G z4*HF71@w?J9Rnk+)Hp34bw3;Q8}Qhu7sAl>aCX>C7|ha*vM+Ydo1w09kqA}qOZajs zXRJpEzG%5BJ~<>O1w71EuJ18Iw?F#O*@%@^v}=fa#l>XAKLr0En8%Hki;2IH;Ed|B`GkcaIB zAwfMRQqdK_DgO0xNcZ~+U1M><%VoFG$O@*qAl#Y2b2MYW+T~p8YMr{}6uYDuWCLZ< zDqUk|ohL^7N%>`Y(9ZHG-Ga4&@8|0sGYbg-$sWa4EAg`ef}BZjU6cCL121rDOME}A zabWd~))_A`5gXs$nHk?zj`P+l=iG}DvR!ysmc{N}m;Mr)WR1OVQ&-k^acHzDZ8iDY zax=-O?|Ak<((gq54)C)4NEw$|-=5PIFQ=b+WdFUGphStO%~FBpri$UZ3va}5ZI)0{ zDAeLmkyxMic~B#v@3iLhX0Dfg;!$~@r%t`l;tASzrxp6c&CkVpH#_@)8f$gQD3_)dWTSBBkd|}vbFbr|>l%Of@S$~2?C0tIs}H1zbQ$@p(ywxQnb{st6^{7) z*>*rcK~EygySZ;%DW7`(=u`JKt&i&7!{*$I6!!=K!5xykJfesUTlj;wt>EukeX{w@ z1m^4hs7GY*;;`C0YF&`n^l-q~VmTAlEm3UrODlFo)Rk5jTnzk)7LiRaj13JRYRFV^ zaL#1DdUoj&>%csPU0u<3@p(;s<2AgOB57^@m$(E^3_LjS(9!>925tHNg9mr2i$?zQ z&r*^g1_bIzaLHTjI(~d;Z&gMYmpnt$n9Sjv@ePOAd48lo|9_dSj z1(sSWlHb~L>c!EoU%u$h7uopsO%0=R>f!7Mo(SpJbAV*ybF_`%!yAPX>&#qSTzI)y zv#nJ1x39iA>J;$hq50CN?X8hq@|l%=ny<8P+!4M};9gqVZh@n>6L>KMy>^JK5fHZUX79MdxaAU8 zw5K%_zw6F(+O*f3TY58P*4!4koqpcI{BT6JkxsHxuj}=)D@&@rfBh5D_4f3cGm(pz zEV;%5Qe$kZy9WLTMkzK~gjsvS!^1;YUq2YkE(hc=0ulmTJDr>!dU8dbb1|TPU72tA zSb)#nB9OP`j6d43WI;pGmvo0n&-#>(Yt?aLWy!}R#h z0CvD!i@15y&2D~&0@@H`(W|7ZF4~0PM%uOB{>F3pdNJ7*D^|1t*kR(GI1YjyqJ8Sr zsf&$rv@s$eGK;$zu=#FpnC`{S6}#_0ed=}J#<+Nxmu8C2x6>!dx$`*G*PJgtXlnY} zG^*uLib#j_IBT+v@ll>2&YQ!jK{^r{_Vp420@BVwg37klN3!her&>2r0>Su+3)$J( zkozzrnPd?b%1}H1Xu5Or<4#w+!7bs-+ZkG)o$Rv$Ny6fm28+0|3ywG@x14n)IR6rz zxcN&BSM~1hbsJddKWv$~&AUO_2@gOz&lHgDo|u@8=2Tf5Z+3A`^(%{IpZS$v6&%w^ z+JZ2mpM#n4O>66F?0@YVKb_r8Q5-tBE`|KkmqZkE^7GZ93k=qBh9)NJwq!%61KXxf z4*$)24;;8FQsVF}iz$$Q84Sh=Zf!8(fuP&yU|WC70$01aJu!Q+yTS-dK7*Qz$m|WxE#dD-J4S z%?P6QYO>5l+PWk6BY?z`<=d`yjPLM_i`#kk**d0s(`?x?Yw(7doE4GdMc!9j2yn_*!;J+v+IA zAu`Z=W;yxb1UqP<`!x1rYo>}Y``^#c|C5F98xYvN?~aIe_BjXRgL?Lk)~~zDuGswg z{tJtRhp(=@W3C|m=+PtmNfa-{ zAgThqhEW8te=G)y{W*K*1*~wr`ae2xP^h-#nZ;Ubc=c>dMxO&&(r+#m{vIRdm;072c4s`KK+n_>6!hqnsO7 zB<|X><$~+0MO5q>VeVb-%64@lEH2QpnA``fG}cQ|s$l>^VMv=oI{9Vcn(@#BtWgm* zlUtKChRm98d56+R{xxtud~Av2rFn5kyg@pWOM@L@AA0DQ<_mEL3#}jY7!a10#zowF zj+%2k84ap+zHEmLdPb3G=aTEBqvMtZ5sllImZPUIsKv)sh=@_kPcKjq-dB|dy~DhbN+xD zlD{<)*Xy9n#L}~~UT9T}P1@bZ>9kJaxqs2lgE|sC###1Zo?QG3$*&pSe)zEOCfq|` z_64f)g^t9sb?eq;c#l}Z#M5NH^!KX+MM^tKiTVe0uArS)c6gK2dnnb&?MdLztjt6O zG;Zjs3ctgtvGa^z-DG~dQ237}i4itiFBa{5H>btQiLMIy%!Y~T*loz?V97YxG2(4q ze|sx$@V2s{A5Jjm*5bTD^GbGopZ$!(c_%)N7nu*waOmp^^KkeJnA=|4uJd4R!Q=8P zb%DiA9+IMxbxTTiQ7j?21f^Ssx|UC(-ZnN8Bb`(PhXS8mbIU=vjGT#+lhbdxKI{4= zwYQBAq>OAG+xRC#rb=Gomd{!Jm3MrD?m!F`n78QBZPZ1ty?ytNn9A>KC;<$H*ak;i ze9Iva?`|G=bIqZnwF~*S*B4i>POvfV^zp0rDO~vI)ZvN?`3<~>bIM3ah2?k4rgivq`Qjwzg#kuvn14{`X_7FL##@k!34B7><^Q3j* z4db`f^e((Q{=}G$XH9R+2f!gpEKroJ;nAa-a?yIn-f}aF&#YdvW`*drUHbE{u~UY+ zrf09JstoSq#;Mfl5LyI8mKWjyTmb__IURamW~Q^O?-*f?j*m`onty}Ok}D&1}n;||B8 z>4!F|sVz{Zdpw2rdMk&B=qy^>LuJV(gFggm@Ej1X8^g*%F;PWJ=Jewk-9z|k88I_y zvza2*gK;cb^2;QMyVR!;tUsJlDjvCwdy5i~w`LBPEHq!eSA2hX1g^+#g>&v#%Hn5I5$}65ddv<__0*tVh0b2IAt#b}q!NyF5;m zI{+cwxr&TbUCjbR&7)DR;~Y6YGjZHNZq{^fpv0RN%O3WaftQ%s zf*BmXjg5`GSIRE3=~0y$X{l~c5p~JP%gVkmf|$8#nt?TxYps;GM{S-*b(~t{btBLH zpSrK~c=)H<7@y^FsBKx|8iox3QiA5s8vLev{c6ydzB*Em$u+$6^Xr&|7hi5)Io80< zn5dwRG6;-x((~s>;8|4nB2L+QWwApA?K~duhKcGKsGmQT*%^ize>@vG;lpR_ZZ^W591ad&f4ie4<9~k2YKlcgC;bO&8T^Txd$76a^)g9wL#t!Lg70VG0UAJGmdM+4H zWerF+UE|gryk7G+N}hW7c4}#ayxH^%QiGqd@7136-@I(j8zf3KnTgvm=~ZQ%m*A~z z?De|hsw#u{Y%=#DzyIAwSy>(zAD2_K=PY25Z}jI2qkciYaal>pQoXf1sSXa|e>_wC zIhRZyva(u!NQH9ECLOO&)6EK}c?N_lwc=N17JFH9M=9qCU)_4*XP)VWjhSm!oG7yrB>EGVu$JA5vw4Ti3?HSZ_mBC z#`(P+LKWwUmm#`xTBqd9l1|LnTsmKrI2$EYX2LMEXJu#m9)f7`U;b1T>35uH;N3VT z?M`BUTU%e<(xP-5-sidJ{eELZmalz7rEAT_K1ZrUx)yV%8aeZd%YD5=sxQaZFgyZV zdCI`i_<+QlsBwdSr7KJ1Be4I@sX|+nfWHP8H{bHBuVJ8Ar0YL^oCfo9MuX%@`?hZn zfP07zft(!Q$L42<9iav=8tn-)B`);LHwy1|P*q*zrBhkte zYUZ-U#I*Y4{gUTsw4gOvuEV@6rwO~Q%T;= zx~wyj0FR$}s%SFMG>9`}&e6)NxOwR425|u{#|j10&IJno&*haDBPE22(LA|(L{r2W z#FxhgGMn#`=D&_pN9Y9yqTM)~4LoCpz=-=g`<+-4&!-#_zAl4Hfs@N`&-*(W87G*? zpZbzNjjZSn`}ONIgszzV2z88~JHY0Bu3MJ8sW}kWJ$M^!+ve#WQA{jYlHT-Cq{PEt zjc)Dh{Q1w>!uJjxahEFoLbSdf|i(tc5H36jnTMBEp* zG*F>iLH%y`@)~?E*jRJ!{c2fR5yJyzQERsNub({%d={6edej+d;bTylDy%EK!%hUr zVK$QDl+S-`h@){Aak08oVu64nlrM`TRvvPMC7eEhE-2N|-b%+o?g8=2M_8FB`nJYA zw^+#hvaaf`goD*UJm zEAG?;pq9F>>XEL>RU!u~7_|qz7RxgB zs%319`0*JDqbJ^NVm1Yas~fy=<3{YuF|%zx5jHHDBS9JUbS}G2_uPZzVDX>s$1!bi z_c$p-iTkM&H2J8-O&OZZh_^cACvO1@&Ef25c!FfMvbdL#2q!gJvD&z|n=&ewX!$AG zB4Dm`xrPp@T;OP@J&4%EOYor;gZPZfvG=MDjSmjUJK`;6$Xi}1%VlJwDZ)wpdzt3= z$uELf+*(##1zguKITFL_cl)D z9oIe-dHFI&Yb5tuawYO- zM>x6lnY05bl#s&Y2^)SNA>(_rAS*Pe`Rd#8LDtX`t_4 z2#1lBbaDJiO?VV=PVIq(6s>y{Lh{`)fa(wh_y&boACjA(VH#T3ET^C6GFiF(y-?r5CdI4aYdPY{QEWWnn;bOJ^b9B z&DYyjBiOMZe~c_)o5G0hv%AQP^vIzOxfiwwkCvOu01yFG;xyG7z&GOkfGSEJ%mqEj z1;R9nWM?YHliT``o7;$BmV)y2iQ}S7)#?x7`LW(hIm=!AIfDJCXF*}u0>?t_K8DUz zE1(lRjnENa^5`Y+DmK<)fmeGW_WYI*aY%s`82>>OFnWVKmLz=lZxCCAFqO>7LYqw2K6R~m4WPsRFnKC9$(+QByT%K*nlToThB?S+)gfTNj&u6*5Mdz!j^4ht-_Bq@udrQy3221cxVe8y zN%!;tqG#1pm?e6_li9i+ZA$kW~JLz2p$8XAciY7J^wG@h|(*vit|8&!1hOkT;{`TVx(O z{)9Wjvh4B~^ng|oVa~7``}{g`Oo1WMaLzRE{tB9=OovKU$XGq z8d|@-lhc`-2+BJ2X6-VfA{X47h_LvsBh58zKb&Z%tmS2Ym?fXns;sGh_io}FJlPQ# zWGYlhT@Ou0h?FNLJnxg7nNhoi6!&jH8Y*tA+V^Mn7u`WgwcoBC0pR84qnNMkEt4J7 zDheeN?%F!mSPIp@#WN7DX?|S|mZ!>!N>NeCK$IW|kBjHIrXUdp5YaQei_IIIt}z?P zIZe!p&768!50X!;+!p)YC}PpzP=yk``U!@4CL5_SDK$Z|-oPHoHz919d$jbzdAd$c zYh3i`{>{I7gfTvM`H&a`jk7v-L*@}Rri|spYAYPbEfj-N2Y83NhG1?nTS=BOMU8f+ zXicqZue~2A3HeDHJpMtw!fc z5-e?uqN{C@2s3(mdi)!Sny8)%J_GfU*{{8fr-=eHxU@j*D00f^7>zSIp3IcCs0J!7 zZUbDE!aqV&WZ$vXeoV7R~qSfB+x-4ZB zXTmR^;U59D?d8 zgD25q9-sb(cd(W%&I7`};F0{8%wWk5-7$D_m-pC5VF+_UiJ%Aa*jLy%eNH~wo&ARn z?UGrH;}8frX;b4`A>vh6z)UUq-Q+jb1Or(qTzk-g{d@0)-Hr4l-{{$cAaje)?!b9z zH`ShkdvMoUR{(KTCku3ZqRhLP`q`$pzMg+!>i>aE(wq|360==4H zn*NV`m~QGBIH7`M=wPB#ONI^K^_SL>Frk$!cwU~|^Ztw?NTwk7EA;#75aGB+ju#n@ z2wT+~_g9nM_gSMl`+Hm?u>#qB=5D7bl4AoR;~XVmIcIOhJN9ruN7RKkDwrun_aDx2 zZeb>8;LEvKMj&$M-3iBD?Oz3>H`84g*q&ArHGf0b+oCG0X{yHbhWuCL3z6`Hw7|gk zm;;qB%Gluz!E_(~@zw{x&BuGVEkgk;I8ydN!R|PoW$W!55%Hb4{K>7Q;bjVG3&9My zckheLfUs^m83uaElax=CDL3U(|s0bd=Dk+%y2m0d&F~qOIPfNdGbJ#du8~1g_4%no!qw! z?P;E@N!N~p;LK;7?bx^&;`2yXax_IpV&t(WcVehsf~INLNbddv2T)NF_j{4U`g!Nw zy=MrasVWPOiK7-H%&OL(Dsiimk#$(0FonnZz@q$>{lAZ%>;){l2Xb))RkC)BdCUaG z_fi|-AS^JHM*6Z=MP=u{eS9u@+QwVAva~UBEe_shMJ%|#1BvIlM}8j0b%?ROe$%DZ zQm8&iHDq8XjO&6#eZA(_i?3BQ4PwXEz1dSajr4w3UU=~$bxe&kFpgM(qDTHdqcxm9 z$r%~fRiqO8QHzy%Q$zbs8W2jdiRdkHDu3+>Qka*Mor2*P>zPp<#H?iwx#()tYQ(>k zHOU=LoV`J-#@vS&k@5c6l~DU5DNv@Kn~9$Tk}nDqwsq@PJBMEF)6j^ff7Uq>xQa5& zjVDL7_x{_X_<-6KktW4VdzZ>oZR}LP&S1OPcPys8pZo&Qz87e8iAyAZ(`>YEP%|zr z&dWGrQM{Jl^tG+1apRy6!%kMbTbZeWUfB03+?49w`9doB_v0A8S_L~F{Gv)@AD-}&?sxI=23k|!Ns36> z8a*~IQXSwj{AB#ZvP@pK>N?7(A6H4R4`^#IL+sHbdL*H`j0}cUd-v$bj~vKvFV@Ct zB*hhJPxDP(k>^s7#qqLrmrChH(PIu>vh{8@_U z`a3mOxRY_o8bm2RTR0`=HOGc6o*6ki>dmAVQrTLn^TA~1ci~Li19DICn8J0OZ1?PH z-C*eY0Nul>gjBBrUI*lru{BEDlPuLu0BUhs)MvP8j2PhRl6TtfZXe7K|Ec)>vU|Ql zba@MTYT@*F`UZA%jaOkFTLXlRU$x8HBr7-yjJqqg-T+Y)UEW;9?cvo|%=ZzBB( zGkA-**{YbS#t#_7WNCq5&>x`&)S8 zRCVu|#wv+ghX4kSqIwnEwM!Qjwx^4*DFCm1-PqdtOdl?St_NloGTkP}UYf7T`lyKR zw7v}=sfO@w@epNfpoJTJe0=ERizCF+?}yK)>ygo1wOSa|!G<%bQ=e0>PYM63*FwX2 zn{R~ziNwmQ`VdBeb52gx<3lskL%0*1I4Rs8cffI}(rk}(cxz4OF@O-$nXls}Aob1m zSBcoPwmZn?VNgit#u{olvu$m>soBAU6PrO0Gg9L+oHqy3G?X*{>b!kL?iYf@HoaVJ(81;#DOv|7#uv-f`+{# ztsBgfUV+J7%Nq#}H=`d+xQtXG@wx%*@s8$SJF@BaNB5uV)5 z?x@l&AR{Q35o1>K7+KsH;DYL%r>s*mGsonrG9G-cO_;Ib`C3=QWRD;&koiK9NUNZE zJ3?kw5=yAD#UxahZd%*sQ!!mSTbZ*rYvtz}Jz{(NuXItaiw6>Rcf*?6~p4egBG> zy;bq+ZNW?LiZD2s_wiw$T7;bGE8okkOHpw-Ho%qqM5e0!N5XFvg+kX&QoBPKlA~3j z*p)d5Pc@;~A^Wi2!S2J^-vjQm?7+le6{+`*;G6e4*wHkceHlT68vRtYq24+XS1Iqgke5!fXh{~_B;#cXXA**7dBN9c_?slGm}qV zZ((#?Do2xnI&tod!fU>H%=R^{Kk_!Lm|x9ha{B9CP#@^=$bGhI`xeFgDNK1C%$C_jra!k`RFQ%phE!y)v;Fm9=xlEjqBGZctTfnG*NKtfMC?HYP~z6>{TItm7H8T{N0J zCnV>`dTVE%1bW!_GGx`4U*yyOXDybCGfX&tcs4FiEK<$e4KPZ=2YGt=YDBpq_?eya zcb24@K988OrD(B^$B)mz3Yz?9fUadJ=B=NfwoQmH*{Ux*`gXmv5VUGT!~6F>A-GtW zdLxz1tv_0(g4ZfEpxRXn4|L{TnrYS71C;jeN5+|#!cW#6{0gzwk5`}EH0%HD)mqC_ zXAy&DFi{PrHc3mrv_9cS=w1wzt3ulL3vI$8=D*f$iMp4Y>kYHe405893Ayr?2-zd$ ztqS~%wU-yIIqP5?;fxF@4Z>J;N?r8+qenN5WXcWal_zd+jt3v%ggnyX-U(nh$ZGmK zH*Rh#-tI@Il=YXGdhEGRE*9vXT}{;FVNVj{_tRou*I8Rwx6YjEYno;`oQB3duwE`xvR7_5+n zwQ+>s# zGf&oiigZ1u1y4VBlCLv+mu@x$?;3mlIQ;s!jg5`GByUhab_vyLZ*_Yi$~mzqaST&W z{}od;Liw5Z*a5KodzWLic1*c&+V{oU_xXNEc`C~QR@y=(|xBF=`DbFW;l<-H71HxBP zG@n!GnPGFVqnw8|zSnIrI1;fah1e?{3-iEZqG^x74Fofw0`N_ppIw4)PVZYW|8C@r zm$b!QVXMBkqbK_*aRa%#l%n4QTzGu{4cOk#z#crt7q)mnfu_!$*>6q_Ta6pYIl+|G0zJ`4f zHZLK_pD)jAk^(=;YBML3-dJh($m~_-R$P%Us4NmJxrplKyyTI~f3nZLTw@gj`o|?F zJM9@ld6=~pgT)&G*R1`2jIz$h5xdvw_4fNQFqFO(Wqg&L_|XNaq550)?BQ8sJ^xK( zW7ik5E~$09xIQ_Ugnpa1*Z@88S0)biMOj z^m2t=^mE!lr3Sd9ENSf9`vwL+kkqO}le8M} z&|){dDNmi#k&9o0aD_o$eTA`JjUg(oKq5sm>SLB&ezDffQ9mkL|yNDF`MFcyH8j?pxPb~Fi1&wHF#U067~0=L!g7Bag2MSvRIZt6Lk%UF#q*O z|68~UWqa?-P1Oy5O-YC+`n>-1cYEL`d`~vNlaf2Kt_tf)1?!lo{jOpxCic&o`r^nS z!djlzDAx_3MPr2Wo4Pvjqw?1zzi6?xV^olqsy0&qXAlm`1;I=zt77G^@xDB)sYvX? zj2JG3&Ta85oQtc`8*nx$IGV&L4`z8U<%S%t_s}$42vbLO?EdgU#`pY~B0b9i6Ik-u ztwOk@XPV z9w$#uBA$GuzUE-+&%4N`NQeYjNNzh$G=A#$55L>wXOCizWIK|&sS0$flU!IE=%_i_!V?FlJ~hqk%P!NDP~DMO|Od2!s|pI)it^V4;D#y%8p;LeMwdE#v7KvAM+-Jiw8 zAPyAm*5>Z=;NLCx_S_L&9M+pvLV>!|MX0D7{5dJ=mkm&?HhkKK9vd2aMHjCX{^Wem zDJ(A#1>LsLXL5AI-yc(Gg0YF3^=0X3EPX7?8&Xd3g=C-XJGeWMqV~H*v8vwx&;QJQ zC37|EuF9}080f&{71vgQKe(wU#Wrg*+c0qVDG*-{Q#-p}Q{UDok=9d`K2ig`wp~}6 zJL;X7qtsKmGQnqWQXGRqX}!wlOo`Db1Z@DHykZnA&TpT4^26%a#iqRzxbAZS&~8fH zDUS#~4?kxqrIba049nb5t?^ zBocu@ISir0+zks{nfr>A;Z&n1U6Fs?9MI%k0hAia?^xlm@KO$&F%U0aggZcN39%Y; zXP{R)_XT{j`2naDfXDEU%|%&fk0=&}GgruqEgCIm-`-l96l|yym;e6g@6_Ntf{6I5 zNSRcF6*fm~A}mXA^D!PE_pj`sL+CQ`Z)j@(f9j|`2wGY~>m1*fNQ}nffcA+m41M?R z;M_ZL@Xp?SC1E+MBGJF&iXQjo2OP1R-{u{7l;fT*z;qsj0pYL?e+lvT;7t0{^S{ z_MJO-)*y4DBbK4_XeL|(|AEpzM|=x{$1jD0gM)}`OLPRyi=WH|9^^fv$>X-nK5H0k zZ@~n6#3R{RSqkZozph0-&CSrWdC#7DWAdIfK{C=50Tq8zflGA-u~8v8ic92=>Iw0w zqIt`a==3F33}_KYRk|D-gP~xA0$+u{A@ zONHta%xb=%QcvqF=!k6p6WH_)R>h6mt_tjdIfJ)gV&&3>{W}pvgi@Qkj=q+-OD(+D zouB_gQjAat({>f9_TL>Um^SS}eAo{>NeC(O6bK*L%LM`$q=bV{Zlfq!D2iqx3965M z*vK07_|e0MPK${E5FY>HD?4UYS^PLSrKR6ADcV1`Z{N;DRI!0yiyY}Hy$qCBHHhEA ztt|m3j^}Iw-L>}q%A_k$s*C@T77+t-tTm&k!_tFvEb!uI(tEyfRnUDQ*)0Fa<26xkQ$xE_YN-Dmz{SVVKSR;f7A?VGy~5gyxx_Tp5%*Qz;tnh1R=D$QL-pvt;f@!O2KN~O zls1X+W2RWnt4Iy6N4%G*BIUHclb`4(!fSuIXJ2lka+WxQ2sXo1?Se&@1j1v+{2(r> za(%&%sFkD@iI(a6u3S%&cYzb)QE(QOexBp=`MS%j%N6<5&>UE#f^E2w%Bp!#GfT4aHT1Iz+hY{Hz(B+ekaD@1t!-yxBLlEA%V++)L1k;Zec zL#TPccfJ(D!5>Esc<4cLF#DfI*yGu{kw8jPQjhv4?;^;Wsd+5;0qw-ImCn_MjiYrUlPHAf@ z(AU<&=xWy2n6JjS0iA~M>!V$wr*(va>8G_sk_j8$)_5Zq|iMq=`4_beYbT6<6AbSLQ4~wmfz;(8B zVlI?KKDHX&6<^7n*Hk2L8gpH7%Vp$_ma4vvwCnw)xRe6hIvx`6-8d#cy=qfdyn*yWR;Sc}Ab=5}0>c7n^*0X4ew zo_Ut3D7VbW5eQE%w}TN`Dv(B&3!7H0UcC{F!G5&Sm?2`Z<{^?`C@l$S0IeQas10i$m5W>kB7eA0@`S7v%L_MnV`O{%FUp)FCY& z6*`*5NAkBTzK7|`Tic{fzTCPEjJ?{hjZEN`A3?@VU7H<|pzxk$ ziAjgWIz^O9RM)yl;jvZhLQxVDBB!`4^O24a_+f%T@2HM|$Q^re?LL{sYU6ASH9$dU z<;U0e1zJDel`LPLUk|@4RgfMPspwWbEuFsfWBS!m5qr^DnpnCQ{alxaHOd58|qnM%1>YNZ#MKNxVASOLod+%y>M`y zj^C^z%L*qc9U{oNdF=kxC*QD2En#TM0{z|s3TGzGf4g8lRTXS?UyQQ9iQQ>A+7)S0^C$;#y0*)rD5Amy?-=3x5K*D(>SOR*U# zn#6gm6x}sH$RX{JnQtQiQfXJ1bSrOlQ3q$|8|Z<{>T_K^`?)0`tNlD{DX!v`{E4&B zEMT1AbmAl>Hg2&4ynpuEett>+INSP4Clg2iVHc5>ZQL{ z5DgceV#2kA2xmPY2HG6IYjxS@nyk`mQ$Z-Y=dm>;1Jws!Q2Y|rkk9Ze zNrc3y{cN^-Ckb}@XqSksxG#>d``&B;Lu&0{T@z?_e@GHZizZAGtdvi^wyti@2`bc& zq~%)EqFErbcetJJ%~3f4R5XAuTC)1Y7MD3Zy@Mjx^7Frj_0}i|B!a#rlT&BO#AhZq z=~pIT1|u|Q-8fj(jE}#Q_qtP^?9q}2SIGcn2SFl|pV3%#0@J9t-`1S_o(~Sh1!Mr+ zh*4BS=6WmVf+ZH(YXgerp%<<63H=DVwV-aLi4^HnylB17YP;CO%ZtoG;Uoz$T}Lxu7zZLF0hiv|v{hwk}u?9-YUHy5X&1K|&Q zQ*${#s97})I(oGUo|o2mO4rRkYw+l`_&d=-7Ypk7!z)VRa*NJ9lL>$3ST<3!C^P4F zcJ+S492TVu^Bs9AZ~7bVs_vcMvN>#Y`O7~)O|;^#xvP(7h32bANH&fC%5P6F)J2!k zsvH+iKJOwGziFSN+Dz28en9^U9(MFE&aGKN2ZWce&u84X>cBm3ez9+ZgCA4Wn6?Ep z$WXMfuB|t`UVLM4K!P#H1wdn)@J6Q97aa6D_|acS+Fq}}Od6D~v&P_z-aVFhw#3rl zo%;IoW0*9)l`S#*WA;qh+pu&0%%}TO3R`tXZ&r00kdCnD&y>wQR9`cKe+p78!Z%d| zFYc=~AcTObn3xe&&b<2;MzUbl*bieC{x&s=T3+;H{ty_@ZH;Yh57jO$nSaJVb)J*; zc4r`m-6!!apju!36vIfF=l+cEbU|i&@|iNl;Oeu~9aMHN_J$}h_()UB|3}uF2V&K3 z@8jE)A(43qm7$Q#6)7Y$$ykZZl1d>$86FL$L}W_F3Xv2dNjwpXLPP_~kc5&nknwwM zz3(}n^ZT7Y-;@39ec$U|_ZqJ2T3}JSC<-X-YU!Y7UV89%QrGt8I4gfTIfMGrIIGB} zYqUQSYWVY}Ix-i0Qt|(6x6`E~!Y=TczTc#xGOa<O;r@7|DTdyyJz zA1@*ZXi*~c?=>@(D2!tuSoy}BA0fvbv+Whw_SDQU-TUY-ABNlm4`dczb$4$F3JQAY zGfe&LS-?QZ3l+xxDhDHTyfdAKDXR@_zSZ)qbv>x#dekbfTO%q8XWl+??@jqeZkxx{ z$L{c26Z5s*9=f6pBCD|54z=}CrHSpHnuP3h=)g_R`wduiavT9XF6S! zA^MI2y6=Ij_xOU1-?CWgwDAy?Ui#b!eYZa+rfp82o)zyEkUw?e({q6%soOTt5+)lt zBcI+dxQxGY?6GF6(5(Y;agY2(<|=z!l7Z88tJy|cLYvT3s1zdz+b^J4I#L_z-pnW; z7PDJ>y5Yk)i*BsuIfzatZz>UK5VR(!BNN+eyJu!*PX78mDMM2Mt02yN!rTp^?rq?1 zxTNM{L&Ham*s%zoC3AGG9C({n*Do#r2lX%u$0Alu3jd76fU|yXp}d@Z3+!w8I4fZi z>26GfDnPyBM}>tj;VCVY`dhtR{i5N5@uC=4itF#|kZy?}mk_B+8egQgPb2y}#>#?; zsPA2TnND|o>bX+u-Sr}#3b_h2^b8E^h(1gH!ta~$jCTU3pLX!37)m|-Vn*8sG5E|v zH9EsOcRqsp4CJ|4nBUJln7Yaa{OPov3@=y5M_V4E50u9UP-zCY^{UFBIvONc_L3*1 zG0iKGE947&bfv$i=R^o;dc~s9?z!fv@_akDh#&9`_hG=}{6rY}Nx_Yzl|^z!o*QS9 zd3j}FZ^bU> zBKw-)>IiP%VH%3}&0DutIa?>;{RqAY-Rp|rAZ1u@kDis&`&zh)d>G}l{G)HFM~VbM z`|!mg9|GGiJjwTB&(#pWY|x8-a%#|@X8VIP?SrHhc`Zuxu{Y)_+(rV_ zv)0&|cA^42+g$fi+^}tuFkhHcYiBxLPX9u)*@oNHZJ!FA)25w!&W;3OEd~i(94l>6 zekpqJNibJ#d(7oalyAyV)H*bT8#hxO#l)SJn6W3dv;hQhaaz5Py(dKV@b9<5k3Ct8 zyPn3>qSscSMr){itfxW&Y^z~@iLt}G96ja?k{;0E>!vwEivNPVu!dsX@$r28Zck3miLz7J zPk-wJ2YUI(Yw0Nt18w&-=138s8)|3ueA$Ni6hf`nl5<}tAckF)t;T3*v3GAH_d0^! z6ar!}5m1E&fexal!@RV72Hzsti+DS4w58ANw`cH6>*de;qrC=R z9qoR99kxC-Bo}f8F$Pl#o_zVvygJoDe~l@eOrHVhIxqN}OUUD7X@=iH^@!E2f>m}i z>8450P<`bI|5tZUHTEy873fk~|2|eNd9HuSKK>p;O9T8BY7)6}L6pmvG$-I*s2BE$ zF%gfw!L3mU8lk&WHQ6Kw_bPu{rRGot!>7CI{O{#1Kl2=p-#vla^y6ZeXYqdIqLClB ze;yJhdj!Mce1+T|jLQ?Ao6$XlOc!a2mZ7fJiip7RQw~UdH{oWqG?Us?I2#-`%XofM z$#qLfZo60MG&vXQoxnxWB=#jqD7m$4+v~@cFpjCU@3YZJ`pSDXH=qM-2_<{&N!SMU z%0G5#br)^tqQdWy!0d;l=VDXd*3F+ccG&YKWUeuUzfvh{8z_y$;^2`-A%Ms189}j} zXOvWPFAH>I3Kp6?UfAUH{U*Q0oW>(x9qZyp@HN zfK|^`qiZ^gZJF58T!MMc27asw&)9Jp?HiBau8XBZz;;wrjSL zJ!HD>{?c+*)Od7xIS7hCR6{bn26%0N8k zBnk6-$sM{)Dmc(|C@(E55uQ8m`fIe)0#B9Hld|F;mlH7veYQR2`p?Umb2se$mL)Wj zZU|hV>6Pr93zKi0W51X3QIs5UDmIYCT~><}qHi~Rc5G;9Xa)%obm~>z)+F*w?jUU` zOEqq+F1Y*2KKQt~NJeIorST`(08Y;H(d9e^;oeY;IXnx_kzT)N%FYgTU=qrV{Fbqo z>P=nlwfc|N=8%lHM6UR6^O>@cN9K4?TPoPG5|CrAckKAo68%k;-}U*Z;)u{@WC%;chtRA-(VV^jEXb)qjQaN|_+|5;(e zfB#K@)9mWx&*84wTJNO5W|xFb|$he z^d0$19}YQT6ORd@&v|@stfEFTX9i%cSp#gJj9U8#`F3Vwj$C=YiznZQ>>Hsa-j{)l zLLSzDpkKG_AL;uoBdWds8zB+}GUz~n-zH2)$g@B#51Uy>*>4clxJ+E{9BpaT(zCms z&KQB3voDGKa))yuGk|dQ!xo#WPDe+#oeXa?KZ7BfoJx|W%h0db2)VvqM}mGixtnD6 zx&0>2&XIqdK+5*i56Y?7Pv?wjy8WjX9eJR}dci%FbU@HLPy#~S)G-_6PYnlt-RbP_tvukO+#5tL-z^@#t#V!Ps!oTGhwR_K zy*?Kd+9+rpGH{iX@IULG3a8CkeQ=g_%$dfr8>sMcTriqtOUppM(iZZSP_GKl4GMdF zFaBff3f&lfhTLWMek~}uHYJ?cC$XFu2e-!m(nK~X?o#tIoknv_y2`}|m;DAdlgJ+NFbq0uK+>+y4cRYi_$- zALm+;^XhZ(b;mcN?aJ?V3;94N{VU=%DH|XVw*4NUC}bgzw%3}N?f^AmEoM~WKBgMTG{?upu#s`?RiizzY14Fy_AuW!N9f7c=`w~VoO8m z#CBnz3t32YX+~J|pB1dEKTYkDp2!YuNj7&#`WbmPW>d*ReE}LGd>zWJ;Lu;UQKflp zlw;oE<3>;}zmoem&N%t^u9|}?mjQanZpdLVSbwD zHJ?}HKnx94=q=pw8P@#M`TF(pDRY8y`i8j_Ad8#G|Hi{|o)3Z;&kTc!BA_cusmd>| z0tA=wM>PI*IwK_nYC2LKLcca|CNu@k*Eza-cytQW@pwbG-}_Ld@=2+h2d^w>B!VWh zoQJN2fDP;-FT^&6peoeu-_2c%BBNRXTtJ%6JTyMOFbx+TY z0W(`O(B@+>X_&7iwL0q+Eefwjo&b*M`nYMj8mGwj3sncuP=b3nKH3}RSEFop;5NYh ztQMv2smmcvQ$gl3rpr*_Q zjsWX;r~IKD{eX4ygQD@WoAfU|f_})I%o8oD7T7}9d-v}{00P@W(AJlGbX82hLG< zEynJuxwPFVqf{e(?t!pajzdV&dtvk5&;XDE6FG`Al71)$^Aewm&5|an=$`t2?i*bx z@~jd>sAFnwAQY5^U!~I}D#^>Y?F_IkDe1Yj*E=*nK{`Ue`lsY$U;L;^M>%HG{5gN?CCr`dV!XJiC=g?*jFCRwQzKwuPE5NfKFK0bo#aP2ZX2f>^AfyN0}kbZlqwLh|2D z-aFPpLnJCf!)vJC>ASONdm#ptA1C*~au2dT2;h#ygtE*+&huRF8z`$sjv{! zhLA4tY zMREI&3(fIC`=qRrXm6xFOl>ad*!(oZe;_h*q=nK{0H07|y>OGzRK1e>%>4&tUv=Q0 zTX1Qbn}n}6L>Hlo$i^Wx+CoR2huB7ai443rbuToPhFl5OzfP_2ku7Pd>*d8nYd`N~ z&fT5){>Pa8Vru>w0=oWc=tGUbIaFUV%yIedw9JB*s*0m?5eiQww`n!kpeX!5&bh({ zV}13-MURHiQrh8to(=yffY)eCXGr{o*=gI9LKf!6e1|709vJ2uKTzNImc^K(>uJ)? z-Md?VTwb@Ua=#y&<@^8o_lbL`5kt|qU6{`5(%6=mIm&*1bnmythAq`z4p{foBKbak7BsUM;$PQio@QefGRPU@-@pOn97ZTZ9{;ODY2)NW*!ME`n_utd^ zqql@ba{LW-TNRf!xXF)mdC_mbkSV|6F&ubV(?vLg!cDB#`&3%I5oc8FMR@Y}o~L#I z^f2VA`SHh}VVJ|7F7okm@=C4?{-LEv%5E_(TXu>x;7!WPcXfFQ!%Hs?p68K$j3+gd zI#;qC>2!qcjkn4#7?$(N+WrknJ@X))k*_a)4e^hEysNeCUamFdRf}tABD92EC8>;R zX*i^PV_!?GfHtT!Ay$6NEcGCLsVz=KYbjnyK;(kUPy(RO-I=iGKCNuV)q$Sp9r+)D zbFqJ&Xw0}K(L*|NhgmKnI?X*5@`o)Ac@$5f;h{wg9;-C>V_PkGI@G#L4Mj!PI{io{ zJubtEe)f=xG~u6#Tb^w<9hK=#`HSok;?KjvK?n!DBnKJ3}x zqO(uTrUcg21%1cTsw*p)OtfjK6J9Ke{*Z)^k@!2=|7Qcl0IWvyl*ZgLU|0vCH!WAo^S)&#uYBP(m5+i zB;aG58}Nl8k6>8Ck~z|f=~j`<#&IlPDp#aJuB8i@gR@f42{h5;^~K2)`gN0wA{@;R zls$jyVCErzaT^)jZDtiC$HZ;qh`WZ3`FV>x&u?YAp*N?D8WXPa;_p)X(#Vd?V)FP( zb<<+?yXFiBbG24)F~!ffE`La|e&C(+H>#;HLB0(sXKVyw?H6rmgKaBxY)MnyfZFbA zjeja0ZFj1x?MkcHHMPU?s)k+m)A*4{fNAmGZc-IhledLO~& zW=$F@bIIF6zK<_s+?4bN}*^?1XkP$|*)g1$z!Xt|&fqvK;O zlu@VK%Za&A_f)6u@^SvQz64v#df-NAY2hZdU3;7>P%HY~({8yDck?YX_wBd`| z)9V#iUue`$R-80BB$NrZ=Fm;Qs8$qmI zPO3{{xQZmn-@hd~@R^NXlfAnfazJD-wx1OHEjw)Gn)|Tt@bQ}YlNqq-$wV1B9cdM; z7mlH=wo0w()?sJ?d{qPHCHFJinbE6ienlw2!^vkApm_ic6#U_enc3O<(W|zgPDk8i z%gfJqFZ1ZWDB6zLh%(wd{KLsQ>F4j?qcOCE6$*P2$;}YzXcuM>B7+N+6I4?PzPGLINYyDK*!n)ViseGWzY?2dx0>%{<>0rMLe5FkNjY zo_X=dRPKWm=u76qp`CpwMNC7g@9zalvuha~D`xREKl(sqg_B~Q;ZgMijoLS?k>PZ9 zc6F`$?r)3a;HFAC2uSxRkFYFY2% z2#8&M5#^p*d7aR#$J&Eg@NprM7<_-6Xp<(XR1a6wF#+7+NQpr_Dj<73NF!RO$7y8mD{b=8)9>{z;tUlMzKK1oOjXi7K&CYa&Q=VHGh#K5C za6hkJ{}|LVUBSjy9gG;h#GRI~y;f8-o(;&(Q(#B)z`ZlY|}#HL2CCnYkDoLm$>ouv)8M6Wh%T&C^9 zNOMW*t%N4avCCFtY{qd@0u+d>!Sc<%KbdkuT-s7gATo6*>aVvnnM ze>WIxv4@Q$l#ad8KlzDTuh?7X?e?9PC$KEyRzt1BZrRRU%L$2fL~B;nlgMgPqYp7W zVHzJM7udi2$a)~Oe*)|&(k{GA)78|8b|NZ!Qjy!~8GA}~A;qOk!_jKFagL>l_GIT= zS}-|X*xK09i3!iUe;v>Bzl7@N=YK2W)j+I&THZQGku!6m^;ByzN{hyqk6Ie?6wDjk z+8!!Z%Y9H);e6y&_7nQPJqgJw0*HkB)P9kZ0Qc9)v&0O_Bu|Y$rRfvHV)S5m_xck; z!>(+*lC5+b*KbNN@0>pu<`|{FLwowL`8tvqY&T0~RQJ3xF60@Dv| z;uPCZzhut6G`oTs`cK71>ZP3vRl%E)cW=WoAct$6VbR1j)t$JM6r;fS(&VL zmq4iQSqEoVT`P{|!E)!LpRIvRYR|j!f;~Zh4fSq>&)#{i**EC1-$!?KBAoME9sYT` zq@0&DAh4|@wYJcUhC*D~>N`5=RO}xYF>w|vV(diQ7CFh8SNGHP?SX593q~B<{T!N# zL*AGOXLjF7aiQkl=y1n;)cvM*13u7rtuqTkZ6Ce!9uIz9m;aV&hF-!&U?43navV}x zjCjv04fyftWK(m=;SL-{W>~$T@l-)3zB6%LsF6v9v0gTh3f7dN!WXKtBabZR(Zl9_7)E^%frfboKbc ziQcsY@owYhT_+wxl{%T}>J`EsLdS4)ms1Gom`P4Iq`9$GnppCH^r4)H2HGDf(Vtqs zZ6M(aR(RWT-(iXxYN9wa#+P3N5lzQ$RvpEl1Yri*`m^*zAN~IZ%|cHYw#fl62$ap+ z1^O%}GMAPxL6vLb7r@;ihJI|B1|w`)9_I@qA{_a1BZOY@Qo~72>eo|WyVv7#W|L#` zGW-*0hho+H_jXu`X>HtQM>lW41y^~UnzM|N(SDoZ`5XUY0W=W4AJI9t+z{HKCrIVJ zAq4N0hT8j-*rur{4ZNjg$SPF4!rGnTsr%hO(AmbO`vYosVln21v*HO|%s8rdBJPbm z@7scLODUu{nLVneQ-=>7x@0Tcc$klHg@)*pat|C$Gb5ws3tE^9uTu6;S6r+LT)jWF zR!WrNoDO$`oO|pZ!~_}wQgU8<=I7_(W|~`gK0GZmafpiG598pCJ9c~RTq9Ysib31^ zmJeg-Y1J4poGRJm4q*n0p4Sw8*!6$T;q(=HLS6>cGv@p8t!tccsk9#XJX*H!PPSe)?`W_o% z>jy4RI0X1)h!~I+LtM+FN~wC$5s!;1kba?03`{dyb>F_cwy?<0w4-*b}cFR8w61{TpfO{(EN8 zTnJHx)7Pn$_NJDixCDS1LSBB{sNz>&7)n05ADot`gkn@R)X9ur3O{j^Ro(1=GyOM; z=Nvf+8+%Teoy?qmvVK(i30l?TkYI6ocCa)pir!Nf!MSWQyz5<7+zuiabr-e#fDg#q zv^!Hh=q1onNf-1Vq79~-hj{*IchVu{0@N9jjl?;TjO_@Bbo|qGzuMKpF6ls?O_LEv zGIvU&xG&?xRZzw3tApoHt+P>(LCF*$HrbFcBPv#o*~ptiz4>);6V5;us}?#(!BpT5 zK)@Sb9-c|F8xvSS5m<+8OXarlInx`R}3ds-% zkV>^BFJetZo7mV~Md5qot8e|U{e-g8E{mhxpQy^ZACXSoLv)#=7T)S3og>q`*5qR@ zmNqVWoKWYUf%xg0>uU5>BtBYCk1ClDm}VcEO5W3igp_~Opb9ytq}&76ZAol!HWPINlu8Y=*EUsN zoP4-bYN+YO&0}d)Zm*Gw0`_x7m7@jfy=(gpAhN@JF7{$YUe`XLJe&*1R}w_TQ>PAP zKHHG_UsD(K^KkCMa3jE|!f%)t1%|UYB@9 zs5c;2`+}YEfiw`L(Q5#kOw<<5R%4+k>gSjjM(aESo#I0=sK2*JztWe|1~tOPXY#C2 zENJ$ae1AcJ5Gf{I!;m-G@YbU-MW+ys4X-F6z|a4t>&=^|qi>q@rE+W^9($RHDhet$ zOc(U;f8q}w5&|;+7o4hXks4Fg?b1>Ubk+Xm@zJKZg>aCut+<5-|H%`_ooiFU4l)8n z()SN4u{*&Avd>amjq0t}7HhiOU9m`wHsv$d%V;1pR)CMpIq55C`+a2UMRS z`rN1ArJkQe;wb&9r)SOx%Nm4gP<-0Z!V5hTl6eM4M~pc5b}wB= zj*QvngTf_+=!8Ds;KBW+rFPp1ng_n>Tc0q$*3NFOB8N z>Db!+{pAZx$M9;-Yu%b6AXmwV>*UDyGU)M0^)uLt{o+v;T*(-{T@tA z@)3R8TS&Z6AjEG&q(y~B8Md9P>!7H4?OGwdRwVZLQA`4`!5SXUHJs`Y4S>y>w*+=4%If_jYI zjjBTaR%81p{~M^Cz7=iHR|~fnMp4-C#EBnrhy*nt-j87AvWsHA8cW~lZQ5BZX&Q?^ zG`{iWS`fqn*Ee-|)1787D51>SqaEpWt?CQkV{HoKbtG^nETJ|_ zt-G3NUEy5dF5ljB#~4oO0y1X9;ZS7&Jm?(RA^itGag1xT7EK1}k1+lioEZ3{z{gne zb(hknA6^dIuj^&W| zQuCUHHVX*QSxoqTHH^MO@ip@%B|m$%@0Mi8ipe5{$F;ls*UygK$I;SS;A1&YP9yYw zAhcdAlmjgpb4l)s6SP*PXjNSV0Q@1^4+Np?KJzM1{g)?+VM8wZT6h_C0;2>;XAiqC z*Q61HXfG-eBR;9ScHfL5NtYkqyqVrxd1Bhu+>i2d;<<3j&j0vdT zf>}mTeDT&;=eexs1hX(`1+&_KeSJW54v))?Lf>yII8=9DjxGm6q{L^$9Cq9j%bcbQ zr{$t3g{qSuH~j@AT<3g11M2dbsp8Ju=NIvE;uU=^KG%v9eZ5l`(KEAB_EBsv_b}0= zT`#b8{^|DQo8^xmKYqRVrFG#8Cm9uZ#?AcG8Yn>o_3+&AL8=li>Ks!^ebG3iLY|3S zcW!1^X_q0PJt{WjS|9LxRpu}WHD;}o*SWE#r_Rz0qUA@rG3oxf-^N3b{9X6V#eC_k zQ#QjK&GQpLJ06QULrDeJ%DHC;4M3v*|664P?*(vqF&64`4DBK3)Lg`QxZycjzNZRz z`W+p#xZd`|(mc<+sa@FV-ZtwcUmM5GacpJLU9^N7Yy0KpWV2W3tUD7?w$bzK{~Q`B z9T^62lmFiU=P`MC`MY1C<`z#zz(r~oT7&jWxsI_Z?6;GZzfxNmGXP5BG|qE zZ8>B`$aKNto|?MU#!AZeZ$27WkZOeVr+2NPSIjt(V``YAed8t`j7|GmiLSZ_EPEvf zIt@5|8?PAa{&k%sFalRQY6%I+o)^j46Glk#s5j3;jOWCCNB)-(&T*@b@EJvXHchHu zr<)jMn?fd|NR7>uvqL$Sod)G&bGup|G%_>NQ9(e4$w7G7$;s(#Q~$RF-ClWup3>3V zJ1;)vSnENy;1UfZmz-JMLF*&{9o!EOM2S~4Lny!JH`27U&B6p_a)cZ-zHqs$gtCR_ zf)1ces3Y9Ce}Au^ki)*P@@+cT%?ynyc6~pyTy}c(_@hDplhr`q@aH$As9boB|B z>^O1 zQvc>&B8)f9b^-p1wN>7t)JS)n9}(xtmpXjRQ+9iFmJa5%v_Ol04rbh*URB!KKj6>T zED5-zo^_ir4K;Lp$7xqDg#_W=hL+S#V~^c30zN6#?zg7?P|>_-$e&ss-8d+e6!u!B z^x%tA<8R$E=U4UapdDbzNw{NoYW6l&84joF+^s0kY$pDESonSa^7+Iq6PS9BVJ^Bz zo5+CHt8d3PP3o8m?kmbIpM~z4`R*AKpgET`VL~@?9+?ATIV_m3UMS-V4}TQ9+h0BT z!|UHcs(Ehm0~K5g?|yBU6whnnYdwKhOJBsn7k6)5Xomt|0gV~pBCFQY@op=8^k{y1 zC&PMiuXQ`wS0caxztpFZ#;_k#B3DDjp{A2O({qnWMdA+_L9k!}hno;PsDgqp2xfOz zu(?ebGeVeOX~_7?zC7}C5F zd3i-*5)gE1>-ts!J+sgPeDC6F(xp>p=h0S`HOW*@|0P1%O&+d;r3qL3Gqe5Ju!CA_ z4{G-X!JD;MkZ|NXykQvyLul+6`b8K{90_$_ik)c&$a19sTe!v@H6~M&ge#AA+?h2< znXPI_iE6`%P?noH&_3RAMc`;c(nRqbXnCHpuRASwnMv_<312f0{KrRga2))4D{p%C z!{WjgeBz`1ek-#$;UW-Wj6eTb?5Pqs7tGvMS9=E&!SA9%5*e~&fz(7v`A`RG-V2Q% zR6X5tHM~p(Y5JeTW*$I+>-TXVM&?Uoy|8z!bbTvBu9PT4Kf{4eloP$WkqgcjMNE8J zT@5%;tj4}K<+s(?3|ArrERg{{(cHfEwCHpj!vi9h9kOQCB;H~0=S#e<$P9tk}C7M6MiT9-pxI{@IR zuCNv7RJGf;d6SowB5nNx%&^M{0Z!)N7#kF9Ok!!dsL#UoykL9e*B7;FO7PtmD821V zsz1DszUlIA^#^lGnSY-5!j(pdiE`vv?(n;0IO+S>#hRor6&5W12w7;IB!>wH7Hh3h zjX5!weMZZoCc8F1oRL252g#K9j zPDKKY9hO=!_Rp3t*ZOD6cOYB(li57{{L0SANGh^C?*~1zEW1QxrR$VmOl?<@cVw<| zgHBOw3u>ns$h3*RFOu>!(U$6&8Vm2&CO3Oss?;(G9G3r?DHOj<``;XAiygn{t=uYe z>1%4*o2IM(uA-Qz0uEWj$jC^*G4T9t-z-ma`P@J7q(*X+-lva@;rimW26}zm!QU^~ z2aX|utFjmozEFt*n4Pi){vv2bLner4lpXnwfo zB;3Xi(&sEWjcED3HsAfwCHT!A*hklMpCL^L2o? ziPX1bW-$09l55d?`VS+4ehHP{R0@a#go-gWr}<}Qvj)@YglB%{vh|I)NLz&n5BzIR7S;ozdGPkUVWGKZi0 z`e~7(!4Pkjx3rjyeEqsz{dT~Beeh#7#;h-Cpz{WNCFi0xPN6K>ubR!KA@MxI!RCO4PfmPw3R=m2p$^k7ReUGp}EmZ+oW8(VtVQf~J)4}~uj(GamM`G9yx>g*2>eRxs&zPU{W7Etj zw7Eb268(V}9qD3}W2T0#zTr1>v;MtWE|KHY)^9%kzDKgKnC_mysRFJ?|llseG~nrL9vWdn*WkLDfs&=czMpEux&u0IAemO=W>p4=%{T(C9jOU5WRnlvB%ZPReQ$h>UM;JO5XDsLkd@+4O+3zBvviKT&j1i57Xg)&)Y9Z zvXzndag_rDk!4&FLOYS1eWtynaEd2ssTdRRzRhy@8ABc!O3{dFEj@7Q&?xv7W?hsYww_KBopG7?B}v@xB<>$9obLLK>&B78o#aQGx(8LD;%!{gtn{@$=^ z3y!FNI`~o-bz_s0dK{VMFt0iR4Y6_$BiTmBqczvbt?1MZ7-1=l+0MZ7{4#%79A_LD zNA$vIIuoKWk%Xg%niLVe^YUiwmEny|zGCb)!$q#g&0L5#%^tx}y4>@XCn%l8d0L?X z@y@qgPKeghojurS_`GK2!U2LfgGMTU4p*Mc*w`O4&V`REE#F0z(6l*z{LZ+(Bpvxx zrW;YVy$!JrqjN`o`JiMBWO(gGN%`HORwd(JC}?aihF8?!G6bjSuBjcZ7&ks>k-XT= zK)U>{Rcb2vIp(a{l3{gf28;+UIWngE*Qnc8)XB$-wil=|?pwc{U=nIFa!8Tf7-|7P z4uV8UrR@=X$~mGU%4ufEt?f(fXXtS$)&aO%@w>=sHC+h~1gSPh3e)iH0Xz>$)=#;9gFf_{AhN$d; zQpXT!3jgEl=|n}_a}%P**!oZ6uN{~0xuY$iQ%ir1#=Hs=^*B^k5nGOq1tha4*q{^n zU6E^i$p=bP|6tJ4d@r!gC$h)afKh&}>i*UwuJdj?LRDGA99?vP*kP**=j0;#)`Q;B z4V}2E;oJA$r`}duo^=)0f&LK2Pw%AD7^Ue1Z1Ou#DVZUqQJ1X4^%E+fh5C6NM!t-X zz4l7xOg}!&FDW1XSf15Fo26FT`gPV5(2^cwfaPWo&0Rl1H%9JtIzyWjXw+y#e>&L0 zO1pLFM*vDJg(;m&>z%+clrt-1WhmhrKEcBB+)?qLs@()5Ib!Mu+C+*tmA8D|pqG9l z2BYe;b92M$RG118%?7@U=P9Pl0<(v_j03TS9y9ln4XsN^9`DFcDDerO;ADBufgO|* zyPd5?7n z(>JP$a(;T>9G6WMT3aXYUE8dCA5aRyADAdLk?Joc&FT_!+d>KSThOWQNTM_X*kT}^ zI8gMQWyumHn*MdmXZ?o8Czk@IbFb6T?_ty#dQ>hn{*rW(h}nhN$pDsm1aWNVy6j*(D21Wm*@y?_yuTat2m;mps?@WIle zSHXu}?FHD;10KLDHlBV&LlkuYJ^b#?n+k1ht;$j&5u-sQ;`H@*(jC~|=Z2gZSvRH$ zoqDV2NLqDt1BsC*A=OntMVI=zJ)ZrTXwK2QwknGDL;?v^eF|pTgdXX)jt%}}8VSi0 zo4TIRK5jVmb`pUckTkxa;jTczSLvL`?qh=y`r1-fZNg7(?OUs6h#)TFqc2{QdDG_2 zvL4XeS%OZ;3VEtkwPBoQc$FcF9%t!!%QzBSaau4cI5B-fD`I^^d}B=>rcnO)_c zw8;`>?v$Kn11*e1e$$4^RzLrv_%9X!`laDO>=X2R@xL()%No!M7|}IKG`Gg5$IzD2H@^E(@rhsM zqR-YxKJc#^JnLL(h|brlU`+2led-kNXExe|tFG2)-1+$U=*#eS2s2WQ$hz;=^dzn9 zHOO9#J6;JhOFjg_v!@4J0-r>z@k~380nSsKH*fZ~x~S$WofBWVbDGA_AqhU+fTN#r zPjV#`3$`Fv3|F5BW%mpP=5PSr_+XxYcX9FcGI{TRw^4$;wg)SC{TxnRaO4*iZJDZ` zdUQMpV;*WO{2_vNvx@6ZLFg=8-5$g5bjJlu9g-p)`O71e!CLHSnwpxbnaO4k`iv+7 z75QHzAk>Cb6!678uo|itPy9ec@vt(jvy)jv3)wv@_34+Iyv@2Vy!Bc(!0rD{%ydt!UIR?H`so?n0 zqqdV5v6^-P#}if&6mL%il6x>jN0!H=r;brlmd27!XWiUQ5}OA~zTI~3k589@=R_=c zk$aCA@?aIN%%glhcQ%u`I#Ug_x2_0;{jE%>lwQR}X9KkWhx*k-mSy4b(BpTdc_}7^ zNkQxzTpkTQ;VD`FZ0hxap}-UBbd#sA=i(3*UKl50J^lcG+jQvES=*n|F%07oR& zTj?RWvtNLNi1+l9A{@9$N7o;3B+E>S^x)*t7=i}|Mw0uXK3hIw{*0ZAxx=Yu0WxwP zCUtYX0F9k&7a-&XO@JF8IXs3C4kfN z1hMR?)wtwRLKuLb24mZ)04<0!yy7k5WJ+BVUQs&H4B@x8ilUVce0RExHy*T5D~kAMw8H|FqwD9t)?u z_fAri-<>l}Dnbw18G}BTMnYwR!2Pv3|Bc=5(q2OypKvBxTDO;T2+1^NYND8fwq}TW%dbphAQIuAGSCD-zgF;haKA`A4qYWXV$rO;sKo z!y_CV3kT?ktt8ZNKjcPkG?^)< zon4evncZ({R9m~T$PLTzcs{Pgc=t2MdB$7qo5MCc^6yO|Uha!a6KX6+4e)z$7>oD6rfKIcP)CM3Vu8Txjc zyO-m`Qes8tosA8BXfpPi6GYWKyx(viq6q|!!?fjRxe>Y!cwk=q+9**L_xQ+Anq3|Tl` zYqikT)60}^NB~&reh2v%ClZ>6Za46wFdk(!Fp*%q?z&Sk#>dOPHY2j~!IESX-g?7U zHt&$~=vFp)u3|7ieL_%>aiQZT=o|N8f=T7|>&}{moKx{Hy51Fzt=xf+((ZZ}f8*RB zf69Xv2z2+5qgB+uYtj(GdqhM;f|Z5X?r^PN(@)xFj=2E>9~cz>vX!=|tl+yqjwrfL zC~?d@`Y`)wy;$5+6NBqTplA!`RVtP%Z{0d`ZcHX6j^l_&gKxx|Yt*A9qY>ZF7M*Zt z5XG%Y2Q&!rLGYrssM^Da4;ky5_W5fo3t9nw21IMcFeg!fwlcsCR?>;+2klk`V0^HF zzu24?Ml{p(#^kl5yqI&>yL(h2B3|iqrR@*M zjR^}6U(Ey5B(=E#5Z(`sct-=#I8aPn4#*I;*HQRMG?e)D`*&pwt?ez6!?283&Tej# z!R&!>8sfR#SE}*`=k572QXaR{eT2oIMwfN@hG{A_a7)zN4pYBWEzW=YuvJ|>IGlf; zk=U&YO!0eCE?@|l1w%Zon2RlXeZQHhChDka{O~`38Yx8TTgx3f;(RMsKS7Gt8 zw7}0&`<9<2!~=-icLK5R)g&r1Vv^G?&M?PPhF40C#vuk)g|EsrUN^Xv#q+iks7v1f zRoiVO=qtR8@Z6koI)rb&IA6FNwCM z+z)Dxf79Ko@>D5=kp|8Fmg02eXCy{*YHBh$x$HOvg@uD^`IW3?lkZou(GeBbCIOe2 ziB|ApGd}(9?2^IW%%UEpfx${&PDx04&jW^NceH|p2u3{*B|u=TbNvH9T03;5ETt1) zy?vH+ia2x*Mm_g%jFrmj8&=ov3(3T9T;X{%S)I|kqH*a$DZi^Ynwq<`Lf?uOh&_{f ztt#&Zj)~?G0UI-c{eJ-1ECSbo_FwFI0ONQyM#`2uk>GnqbQ*FL%&)?QFvVf>eP4|9K)yZ!`PM1IE z^^JZTCEo~b-HVmHGW$GRCnhGY$2Y)yC=|h6Sm_fE@Aw)d!fpO#`OP3OuttP4`4bk&fYy*LiAOQyuL$PK z&bu0$*X~yv*~%mvOIxaArI#e7Fn>M#p#n`-w(edG{!Gd@^4C!j0*hfK`PW$@vL?>n z{(^+ynS7%~DI-G*yYkIg58cQSwX%l_MxBgNC1aXIA06LnQBxTZ)7iZOEJLON0|OwG;QgxUs3Go!5!#)yhbxx zBLU8jmGFNPyyrgk2#^(|_3DccEIlqy|Leq0Ol;T^Ro6kt+YAC_`&p?$+a49YjRVws z_NI2Hn6S*ZV&vCrM~-aC4pgss!G9fazHRGZV-D+N)wS%%L#O)$m+2ccNY3(jAox0BVEm;VR4i&V0{`{G%A!UL*1mYJTve6S8kNJ?hj+t(K z85Vga+sC)Ej*jm*;?d&EWUIzv9Gmsz=Y8_OAB#3v!OpHB9UMc`=dDZnEk3sJZ-e*= zMP=n11GUZ3hq2v9_mkQ{E*-0ih+mI&5YZ?5jb8n_{gYhwtfK?58{`70G?>|yn zwA0}r-u}jZr`#u%W;IbrAJ_$*4M}9><$+-VLOeeZjiAP8g{33mA3@OrS`=-pUq63V z#Gs(KCg0nCs}S3V``$xMW%0TPhVfGhs6L*QwJy0~W1crAe+Wg9*lX0E{6{L}^ zm6Z@@j`;ZdPn$U#U#lF6EK^<34j6%!i-_eTm(6PpjWw2Ay>41Z>O)1S2r#eN_t$QH zizh_)G~hjB57|TTwX~zFX)=ac)AZHm?YmCmQ=@k64n|GO3(wJs6yT2ovSOQC^p$Ps zemM`gh!Y{JK46}pSOfo%_XD^3o%Gw#nJ7g;knlIb`&YUs{t0(l&P`-qEgu<~dQ!Qs zW>t38Pjwb!_Ulhr6PCUzEti6B zwgyaoRBA|hLJA5PlCQZ-?3v4?g0pdIN9+VNvI>uGzV-O=4ul{CF?zf7_HB==3hNs2 zf+CxOkz18@j6ZPcu#h*kn_*?h-EHc$%-jW|SWjP6aH?NUu;-@-M|;n3*rBaT9;wdy zHrW0|S%#-dl`LoEmxO!PRVQfMW}3LTxa{Q{xPdJCU05-!s4poO6hYg8q5<8lN0kFP zKIAXqfs`)gN|3(vq7?>yidD(P>EGNZ9L~8Iv<^>;x<c88))Yvcf@NJ9|Z z+Zw7Uxm*hC0Et@7rL&IGWtw#FPkHyTZb7&rFP&X$%r6Ci2N58n(%fztClJ&Z%D5*|l#8M!W|S=3dnnqV1}e2S+FknZ_-)Dyp0$wt3M zUKbNloUwgKqch{Uy@Z)ewjH|tqJk~70f$Y&(D>J&T3UP-?ij-$gNwIm=9zH<|o&N!hbs;C{M%nUqBsa$Bv8o>$yZ zcx~MWpQI$ zJX{G80de<_V3Mir#oP-M^M`{V>$En90{wz$qMGjJ{##^_8A-e^q8m%CtSww~tdywgoa$W{;%VY3k??QjM=ZaXHT@ z+lfIdQ-aP#J6Ngu-r_n4}CMhG)X&w6U zXL0R&gTbZ-ODVba2N*+bj2)KQ`f~o*@mjU5U9=!ACa{6uf*j^8=5&g0;_8LmTE7Oc(Lt75z7>@ zKR|%xWd}^)-la=7GQeG}a)>q%a4x}tNt6!1`QY8MiKLQTHX}Z02TVsxhv%s7i1Jeu zZ89>hW3kpRNJwc&iNBGSQu(;E42YDI&c@d5ZAOr7n`u=4UA)@>CcsLyx(M-t#mmO) zk_}GT&Sk_>kXs{~Odi9fPWZcV7|a9ES71Eo0@<#dE%>|G`S=?N{xLNBJKw+wWtQE) zKL$0u8VNST!FLxe@9WS)sxIG4h#)i#%8Q1KXkwekEC{Da;psWV>D9nZX9?#gZF6K$R~9 z!{PcFHbvBO(&#Sz+VV0*3nxV`&x`IxujJnvC zvUjqDh_b1SD@VxQq$FgNWb=JIkFNLU_s7re_P)Ju*LA(l>-8LuJ?@WG7Mi#lu5inO z?nEpDGCml#ybsUU=KUqy892;aGMWTOWMxEi*D8`XJ?Hune^P2~9bQ+k=_HhCKqX=H!7bWsN7uxzushH=o%Dp_n zkDaf4oCb#B(hFfe`;ZR+WHfmERz+z6WlWxv(m<}8>emqASoELIxl$TMe6$2#4H9F= z`ECgTT>9CDV;NQVdS57)(T?{2kb}6Sp@nJ#JF`09Q!m{UXCxVkW$aH`(ktsqgt`rT zI7TTNVv5s_6#7yvo;`CbXun|XSBA?wy5y4?u+mB}Kz@S5 z7qxb9F>%h@%KJk&@9Ai|XsZw>E(%f6GuePRvgrhs=L@{N#|Y)2)Wr!KpuJb7O2kgp zE$y1Jy{zRxSUc*d%Mw#+*$`8jc9%bKMLm~w3CI7+|tqIVG=bwMd(vi{G03?SE6;soZ zi@L*?iqALGh-n#U-3DU$UflkRqvzSE?Y0eE>lIU57s6rjF1%<=Y;T-}s@7+K9$WQ< zU$$odV!YtLSMI>mh?&Vr$rY$vE?}&e5wd`g7tyw!ns3UVR(0fnK3-~pzaw`3iIY+p zNb1T;04UVse{KLFra`v{eL!+AI4thhU1p54UG>>7rX9B_Ef9T}p`W5(2#H&nImn3;_>!^N@h#=QzvQZ}$v$-h@y z!7n6yoP5ncpV8m`5v>#R+D80{Y|yikP^Bi2t@>alTpg=Bs=SHjTy&?V+bfyTDQmF0M|xG3`+51Ne|? zrDqTLDz0Uz#}}zy8Ka;*WBDt-8;mbcNTk`uczPzRfxZ;4exiP|_=c z9Ezdat=dVogD?MWy;TEz&eUydW2r`wMXmHs$&x|6&5f1Yg-(0&ZmCB8D*7(9YdwIH znb24jGaod`9Osbp>$BjQhsP^lX)4wK{Q1*wb#OvfUlt}j4yC@Nj)T-LCZxYj?9K1$ zFXpVujt%8h29Nqsr)9sZxMoaSp}{h2?E}YbZ0p2v zAe{KPlP^6S0s8{dh!7GnY6Rhm!N>e5ndzN>`uuY;@WqJCjL&5q>F1uGN^|B8LIx<( zZy5BwSB`#L=dke4HQCAxffM+=)1`YU{hrree$Qbc6259YflZmMUb;L9TqZTr(<7lC zNfUH=QBl_Q^=l_3UR}Sv0M*l?fBe*!j_PY9%HkAI^q)RydcCKYn9pFugsisDQA`uQ zt*M0|d3$^y9J-#Av3FRZel18(Xk#MV^#jGNCgtV&80eq*Kww4$HIX8eH)DQoO`Ot90Y%kAYns42tUC7FGb~*L`ddDx#yUr;Hh& z7R^7O>Fzh_Il_35CB`~#O1Up#ndaPGi`9FVk@MjIh_*imx!eYwo@dCm-LLN)vFkj< zdd3$RSRzwK=%4!c2S({2WLR&m`DE9eGX=JI$^U_8O6_I3iuSdj$yU<7x$nattQQ;a z=Fp@`K>O=WFk4FAf6^>$XM3v|)oGjev3&1cGa#%E5JSfnOIs+;iDxv?j9y%PLU9BAGE60lr#|13+c`c*&&UspfJ&D__K`7+ zxVkM(-aXH75Qx*kJG*??SQ^ceW#P^Yu2^hQE#p|W&T0P4EuXB7D@qRz zb3ToD-OXCCs!vH!@TWa~?F5}s*SM^Py7I|m$*2JG^>>`uCqDMtR-tiec!HJTwD7);JaFhx5`-zkfqE7Sy4sz}Rp`3n>UjN{mt=@;WL4V*-U_2whn#wZ>*D(>ubz}P zB?mu@4zi})=3~nI*D~1|jvs1F+lyQGMOXV>tMT2azm@MT>qoANj?dT%+?q_@yp?Jw zWpdIfR!*WyBhq~WYt}W0%qAsFAKoRtTlJh($cHOaZqWXP72kjM?8xHpm-dIUp7+x= zyt%3c=hp~P`QX(_sw)pvHWxyB?>kO@&Yc{$R&q%GT{`ILW1?!V#xJDFfGVZ9LGKlH zM;Xz;8GPE8a|-`ztoST6utxn)1PjK&oUIedtu-rk%<2i}LEeSN8Ah{4y3G~k|$a@&%o7qq%aLsadHW z3ZjaE?W=~EyJ-pT&%hgTBl)N~!jEw{;}t6Y5OO`*47nzCjem=sPMgRL70IgwFbba%e>FMAtCa?Pp<`5FqRS zD94%cQ7UPGC)^WGA|JA-%8}+$E^w0%rd%zRrJuu_Q_kA!k5`kFdM*%SQ)>Uoyk-lo zVJXDXvD#PAFbD;C4!j&a21Kb7DotFH&R@BsPhS@|RW;aop(5?ilz3evNFPQQ6kHZY(Oka?#>SeUw&5>2PAx*$4}4QIkbwi*?vn;ypLW9m z66ChHcJN7uqN}ZZ4t+h4asg1kB3ZJZ9AMu}dB6N_NONIGdP~0v2 zPsLsctzf3mR$2`;uck5Lp=EteFnrXJ1JZ_&0fo1SYDS5P2njhRL%swi`O5mjWmp~i z^v*)uJbWh{;GY-53Mj6q^yuLw5GYtog|HI0<l3s3yNi>@k%OxoM z6FXpsqF)qZl*}>nT(BP0W znl-!=JZ^~0q;_RDe*~WxR;e#>a#9aUPB`FgryBkb`_?! zq6S_(3KRILCrPhdH>cb?TMVB4pDCShZGe^AIs|RSTbHE4Xu?Kkn!-KvN(_MV6f7v2 zt1a_R8`v_3>petQ5(lB+ZO?Mlxj`-A+|L+cKHHGVykUE#jxasO@XnF$?$;k7t%PDA z;R;59Ko>X__9x)zUDnVr<6(SJBB`XQG{B`ufgNT9LRL^vcrksjmRDh6WgQaJg(!5J z=BvB=Xv%&<9_Uy}3sqNWNw$@L0**eTjzzdEM3AoA9*0Ch9GJBJH}VpTyZKu*A~ys!mtUNnQO@;H6R2Kg{X2N+=2q_$7h-Uc_Xg|XBQ&OSB1jbssBQX zYyQYlVP<(JTEFc5u~m?xw}No*Nr*3E zSPi>A-q^0m@H&LU9Us6>8Vo_0P6c`iexl?*!*uK!N}?QsATCPMnDf9z*OHpT50!K) z7_ialKxLojfMH)`P68NMm?)_0vZa0bA$oJAX{DDL1Jn|w7MF{=itJ+Gzs^T7DQViy zJf1#`JN2xVI-{`r+lvxSCr=KToeI?@HV&Dh7dt}tLbAptgvrf_l1-nKfdaNUmAgPI z;Me_Eppi@wdprQFOI@zn0X_f6x@ z`4)%I!T)*W3iAyBDP7fyp2p$mg6&Zz$RY$46X}uPHQN8%>x{?ao%v%(q3P+%?072F zaO@bKS3Y4UC6*EZJ$>>#>(8043Of(jzwudvPH`_It$zvZwU_#V)4R{yTKoF-Yy2|} z>%`?lK%~~MKZf7Gwx7=EJfD!i?ajQ?I&+QQ8VM#lFDAwUpV*6L<{%$W8Av{SjhG|NLiFs;SDW=BpWuW{XAUO4pF)aP^igef7<4Y za8w~_SrBx`DB!*c;9#)#NRD1Vib_AoNn!$Itd})jR8)Aiv1 zL|n5fZcnWMw2HV0<^3BHd=^X_A^=EC{YcZkcqyc(yFLjjIx5ciH%!A#OalRM=lm+7 zhkd;g&Ceby8kO2JO2ZO^xd)gh4mU!HJiqNbpw{7Unrpv*Aeh*WnKL5 zO#zS{gv^18sopO9|=$vDUI{C9k zK!eu%cB`iNqZ9LeJ9Vwoz<$a(@tC1g%3>W1o85_&DOL*Iz1C2Ko($;Krcmi(*q#MxLkznr!uL?6_QY=0T7Q*?%^%0aM6ncku)1V6es?&OwNSJU z)VTi~DQj`ciIi( z3%l?0%J2iFV}>{=D^XW}G|fJrUkH7vdjw3YE7c))%#IP5QC78ftUkCVqbXPxHYLdU z#5K1>9E4jjE1X~bHQQI+{aGjF`P`bJb%5i*0cS3XLxj!sm8xLY)1DpxQxVS_U^GFY z;g_kNY+@Di0P?oE>g6p!B0`t&y01T1^%%y#?v6S*LE*>&w;i0r8cVB`tTTR$5l-;w zhnpDeodpvXK=?6~(3}?){4?$a(hfy#{LQ$KVh3fL}$&P6wD~eGg0gxl-9Y=A= zy$3X_;W?S1->~tvzO1 z0B#{Y}mcHYBcaWV_5th|8o$mp|((!{xg$$w)P483o&posU4q`+$l1&Y&c6WLLz>VbMLfX@Xdrw15}7~_?a_M$rl_=1wxU(YcUSwR<#7G(@Y zE5*_ROjf7@RD&-?O&_#YvVd|rKL83y`2?`RubSAO!v)Nd8AGgdTv=tdgnB+K--Qb- zirl2T2g1c}hCEPKR#H|OYZt@jvp|kPm6T%)ee{9r#nzulKuIfCVIkBCc5s=V|3^?D zP*ZL<@QxqDpEyO)yi+g_Yu@!V7N(d0XG6nHzD3GnXOqfqYV0FxJlt6zU;tvZ3k`K? zyhJH5e}rtKPl$3y6puIwz%(34mcspdLMvM7_S4l+4d>TI0Ffhf^m)#nbAvW{q1uL& zS!{a$Qf38D#r3^NgKUVviDykYeGzGoUzuUVH&7vA{dyw-wm?;ixj0H-8e5%kGUNB#-g>&Ddz+Zgy!g+1b6E2xdt7do<>(*q9yFB z&9RF?TwW;_d63%7ajI67uO#xD9yH!f8?!salS8v-Y|Kl9F{ZkXw*fUbb)X5nYH(Ry z(2t}4Cq2EjNss@yf5ZuRU>&ngF%r!0fb?lk4)4S`0(WyVV ztBjhDv>$csWxvV$fn7U3YBp}#Pr|SjWYqYZIxL-#=DGa7b_R^7qbI<6H(kCbw|wu7krhq_6_=lVhKBa2v?R;b^bif`@XxDEzz??VTSuo-J~dfF;(7Yw5Sq(Gejw?$XWb|Udy|+ zrkocJr?ZMu(?`WV;&o~mpw{Jx5{Ht^ZRQ)|G1Zs%L&B)w;m2e-Q>gK37>2H~pI+>a zI{-f@a4%OoG%rVfxLL}{yz6y8SCo9=K31Y4n0fONHgC1FHhvbL7qgX9I9NxSA8EyX zI7i+RiZe2sd}6%|JgyK{!zo33n@;JyI4AExTl?M|ShnYp-})E7Qh?<2>m#s}x5NMB z3Y19aUi;mAl!jQw(KRq4;dqyVIDx)WY(wGt^FcE^bN2w<$I`UN!FIbU-(1yKKDqjt z0u*T0p@aWI$-qIH9^$0Rm6LwoM3X%}!vIR7X{lXUvnKMGkAv&1X5=8Z)JE9wZ z^CtOiuGB!kW6jfK}fC8IALq495nejO4!i$q?D|TX~)I0cyxN@WH6G{y+|D;(j z=Kd)-A%5?cQKae7fT>66Q(P}%8VuvlHe88_IsIUgWOm+r*>URY6VP8awcGs&iBuoS8X0vr2tM%JORJMYU@m6livn%zWV^pC6|_S^t(W zwxXy^tEx)8rJ5qFz>DvlrN&&KryZkrJ-x)vZjqW35#QcPovBlHPrGB&TZ8XbQ%=N_ z_D-7~m94YmH-n41|LCcx?)D5s;2v~iE+&kTNbYdU0pQ0;&|N7XE+UYlMkviJbc4xy z>xXtV`;MMGN`{f$!;n0|fmY0UA3VO?a7-?h?yQ#pJ48P^A- z_4Md9m$RB(4pLUCkeTQ8U zSuMu>I4-yHL2l48X|Z*PIz%Gal+z<=|>{bGD>1xJYu$I^`gG2-FR@@%jKep~ws(0_2yw;PPO_KL}`z+Br-H;7DOmb1_XzJZ5HT~h$rH3{%?sun!EL?8-3&4@8V&m-I| zM^Qc%D!IGEMRD~PKp}2*1q)U$-vZ*Oea?f1bF~Jo3Hg^>9AK7}u*n-YWWgNCEz4p? zi^V4e_e>+hC^wfx*dz894Krjz-~ILtdhTofptnU%A0%=EZZl*gwtFQyulIw8v+E=z zd9XHt9X%B5_a{lU>|1~b{!#<&-sKNE%r#K%1*1|lql$k!X;^kYRCo^ZaPegyir!IT zcORl2Q!zTX`<;D&XXgEuuv2UpbOIfE34ysBCgI#(2S3K6g}_)_0R7TXT^`%;PfsK- zgb%QT<`>VSHNte0t{37kb0;DniOypmfJ{X8KO9LT--V0w@B3ncuOVG#RD1rQX(v-AG^xdXi-FzuvA zlNf6b!1f2pbbR&g(2+$z5bXN&$*Br#`4=#I!9nRE+&S36Y_M;@x6?io4M%Sx{O&gZ z>?>*N-2_1qkX6L&xxH(R;i`nWv`VhQ> z*AW#afBeuXyr#qR#F1-9sm@!tLL8dQ3kc5A>+|pBoZ$Tn&@pN86^*$r24MyBSphco zuk|M!`amxnoDfWd+-5$?1nv~DZcjyve}g-q?rhEgx|SMw<87)C_EWV;jbt%`U7?UG zMznlbv3C@|z3sNRv$kQ%+lSO<*O4hq5!e8Qp!t_zMkbj-MV$&p4*qY`KUb#_0-ij69-8PP3 z;#O(c-O&?e|M$ZHi%yr?)oWWQ@cs<`H@tlnrzYp-tPU`LY@p`DiW#>_q|zhi9-#ib zf~nTzDSulpp{@`DF|eq%hc+ECNZ>y|%wD>+4>KfVL|C)#ZZ-fT3FgunZ}T3!05Nn)}Jful`G5{+w3Lm?CiPj zP_^g);qT9gWQoxM7mv*Jm#9EBC|P3weL&#`5=#5>soXW8p9GLMSKP{4{8s^9V>u%Y zX+aG0ZR_jH*2=D{`WYi?q56)n6RRb+?YC(_vX0-@G9X%LbD@FL;h@Kl!bT}F56(Z; z;79EbXe-1=e6yNEgs0>;x+*|-Cz4g1( z5LU!4eCp_c?!ABEQJ&BL_b5AgD+T4SBEKJS3lkM^gKx>xRb$B8z5rblF%5O9b;fXZ z+m{y_0rD$Xb|JR4G>j+(s~Zi4L<{jKu+T{mn2nQ}^I;bo*nOWsVw)@y$Ug`Mfd^>C zOJ{l{HMmtxArx2&(Alm(dWG>K96g$C{c!sKann(!t#JWI^+zzA6=YAF6l%&taH~4cpO&$z1&9m=VounD@Y$fOk}#hRM*BA5!~jnAHW70e z9VvtvdkJI?CgA^aup|^#g9GOk4I7FF6L@+AEMz6}fq4IOs~I;f+;EI+hLCmNV#Duo zfq9WSZsbfw8(YDGa2s72!h!ei$29CoI+%NtB4vfVo+?eVmUl2@*#&mqY_Q_yJK-if zD+QMf&7PT=ir}q0xcrX5BBp*t3+a+w2av?maG(X!|Bgnzdl^~P4uYYXxcrvE*YO^i zn5|#H#58D^6%OSPfc^?-B*1n--T?h>26&%-+G6AL8}PeEW~6{5u(-fm&9#%Mb=1Uf z+k3VMx#9CeVE*0vHOPZVY(iLNla0*jI2YK1Xl%$dzx7^a=w91?sX9x{t9j6857z`` zW}&9cvx9tzr5z(91<*+Ao}ieD0rm)ykIW^DbsejFAXDHoe~-BzA4F21nYHm>5}RXC2?&%wg{HV##M?+Ek7Qs0`h+Aq@HUXL_n5 z0>@87fyr$jf9I?eu}8zqa|8-DdB}n%r35Cm{%0uNZP=|Obu)y+8E^^L?~@5PK=}Tb z`d9PN_H*ZJ&sba^z+>kDPCFRZF~ms@g+^N0va`j$^})6RnyB_Z`t3gi(t)+GA-3l%E+!97DhOG9$buqK4QwBgrh_h*7klEfMS#fHACEASpz zThEzodY^}KB)Aj?P2iJn0JGu&G}+uDQT;PiAE{@I=m#+^Avgi!h#1U~K$fA0%z-&R z(g1$P4EV5#X`|KC7ZdT?#;)G(DH>@ zM}dPU-C_|9jY*WX=gGA0vY)_JYwNx;YCN*q{U)rU1%25JuxX|4{D^_}nQ8v48dz{Y zFsQXWT7y}>^%qNP=n0%HiyfJf4%jKoc?k-Ra@d>q35I|35aC0%Rs``52&=jcn{Ugrf9XfXu7p%NhUWUDf_AgM0Mr7mbmTQjJcP$7Ma?1g?l~L@qMtAmc|)f$v1IlPy92;xvOU1ua(UwxNJI4zXX?&i3Q0=jeE4MY)CHbZ@p%x zD^2D;b)FCyc8tO^XCKA1L~E%r*5`3jDb{Ej&2eoBAwR!GeZNKA6lkwy1L)Ei%ZR`I z@WY1>Svm(vCrWLL1UQwrC?1DX@L@06yE-Z4T{c%HYD5TB3rqEazCV9=LRMOc4PYUH z?^JLdJ^IabN6)`SFXE&q5AUZ^#ms~g9w!DWr|(1ELGn|3zd1NN|BBX@fFQgPv@q0x zyHAf~=p zm?Xl@=U;6>q{UudHh~e6a#7{}D{BjKTP`)@6qsid06CvIKmFp>ZP-N_VY+)sp)RWP z>hEgX{4zenyeRu-bDOli*fksU`MWm_^wftm#2h?3;*+ip)vo(|;T*}zxD72gOjJyT zzF@?fekgk33^+6f4_v@NLb0&2!S@YBI#Ci7CT(MiDjn=ich3hzdwJK znRurk2S+svy=4r0_v}fCE~g@HLj4PaYJp*ijSzvxK``Ijo=z6p)UiM*0L2i zPA+8Emd6^&Gn~i2~&9szqyv>IYs2j*2~RizDBfswL;3~#4y%d z?r{5}22r7w2I7TobHfbsbvjf0o}{+6$M(%*G5;1dQ)S>LIly2Npct_{lLQ#xtH)>V zoCmJOW$sa^Yk1WnHQiwlRf5Kp_z3Zcr-!A!k$w|8Nf#qyFT~TJrHHx4BSO{Sb6$7} zjY=}voH5A=8{H4cn|Q`x3$TjjTnwUgApySj*%9!4*bf|dsF%Cn!ou>Vj9oJ;pT-?@ zu@~vn_VR~6d-hB}?Y5aOn%-uG?#Z=p9xT1BUJnD`{@Pj`nydK9PTbz&Plo@?0NRKI z__UA%yj@#@<>R!;Qu$LY2_ZQYXU#=NExrhWj^cZf;I%!BQTfvZoHnNFGofdOHZHDN@e{UKhYTmT6?i%vS=Oq@ovv zfW5*H2%nw+IiT?T2B&DAe~^&UPUS}Oa&2I_l3<8(E5R#(?oHL;R5dVQ!JqHw1lKJl z@M}FV`{;R>jeM1fdSZKPgEkH38VA>fi#B$AyCW0bvSFUy6g5UnbuxMV2t4Tq81-Uq zZvIZ(^1wZVs4i_FEwT(`ECCr<1Zm#BPWt8{nAOOwiauu6Li$q(GNM7;QtEj&pyPZX zugo7F{?*@8{ihi{4Q}_NG~ge8e?M1~Kaktp^7;bAWIB7QY~r{M8x3+TbX{VnWmDyCV$Ei06tp_DQdVOloRbP?;Ejo-vK2q ztnCCk+sc~;-#R9w-M7-+?*Jr)06JGCdXP%f9gt;O?lFkE>I*}{tE3X5PnQ6-LnJWJ zzByeqP6|uW-XlaoToHK^PctHZCdmt2^%BIx%C`^m~=5C4i4AX&oig1QU=!yRV_xv-#nl}qCoO3_OZ zs9f9tqT~)b6xoSNJ8t$vhr;x7@tm*DcjFDdO|qrT!xpe|Ysjm3fu3^%@Y7brhx3(i z`Y=bOihK72Ugf>GrG6KXgFqA_2R2Yj&}!*lwuXF?!*F2OR^VIXiaS25FJ85jA0ZWe z0|_v~$#h*y@e@a@y+v4vdwJo#^?K^vt#Dy61&DK?+{ROWYUj7xo}R14NIzDl`3GIA zfdY>LP#9&zH<)V1W4tI|^4g$`FUM5hRnaNIW z&+pGT;j$P8Vz{)`xj>VnM~r{}k20H^Re|_1)&`HhaDz9uje&`>dZx3rALb-Uff6Uv z!ms_k9@k#m#Yza#rFGe)tHGOp!aEMAy(K{tb^RWgW5J5r62FW7ZvP!@A3b5^_1UAZ z0WhQF4l)gBD>6AD2zWbJS2575T$V^~^Qv*|CxOm+f{ylg<=dcMn2p4?=@f;ZL6F=a z+raB6*z9_h&FLAFX-2$=w);ICirNXLKJv91v8db-KXv!(nU1Ph-eu862~il?DJZPANirQi?~mC`y#&Yoxn#wb`zp# zLV^_jQYtn-dGw)-^IRw>1S@8@NQk1MZv-O20)GODiy&D2RwLo~P;1j|s3-3ME`?H_ z|DLEKivrL3hx@l+ogd~vdg_B(!WfzUuH^*%<+`&DARlF);`>72znH=C!e85|Zb?Bp z?C(=m4IT#AD$+mj*ZdxVyb2PieBOKXd4Rw}e8LFQ5&mKVw>7YT_3uY5Bv2nqmp)hi zSlA0S>}GJ>Qb_&5)@TxZS0^JuO?-ql0X5YjoGIrZQl70+(=RxS1Z-~)l`mE?74i~v zY|wCoqj22c50bw?JmlDaE0Z3S(r)}=p6&wUia)2ofXT1?)s%a5O#4&j1RhPeuRaO9 zlZcFF_|vd^51K#uLy_HAup-yoYZ9YBF07k9|Fk^b$t9DM2m<2>Vj=izx-tJO@KE`) zkromJRI5hRhuYrv|3?HEPb!l97)Df^%v~s|S-f7eI0XdgN|waYKZdK;vXScBwhiEI z#u`%#MF1^bO#r^%5+f)w*rtOiz6*9jJktjik?`y0pEV;^RBTk>#I#F@yf6O4WOP{Z};=}+6|$399R+iZaQ2m5cNKgK~QA~GcMkQ zVCBe!=W^wbA0SLOXCd?CdwuFLrFABp694g=6hukVLS-cQ4k7PiVuj~UheIogp8 z8B_)9Fu7Qe5S=Ks_T!aI)Z&I)*l%%5E-y*)j!jlf3@*_}t8&y-%L{f}|0>GFCs}& z>(pg)mOzR5*nm+0Cm2%!<4YRGcb>BZX9CLg0{jy22FT3)*JT3Fw$@sF8p2^d4pDef zX#9FV5w_(K!#xmW2ox zg7~DQO~0{TAs3syTW?+gAM)f^AtRurNT3`1kjR&WGWL()Z3Tb!*#S0D|L1`Mm)Cw< zn?H&>)Kn5Fu-~N}YUl027;%w6{xF4SUmKt|%KEI6{I!{cIhek{6z8FbTl3tT?-@*& z9R>lvJ9g{O$mT#J%2(?$X+8@288qMezQr0S_*#fS>jEM^|C+s!Wqq=c0Nr0FGfWSpqM#4aC1 zjdCT1r{QqNi@;o~HAiRU`U&h-3!=ec2lw}!YGgvl){*w3#VKAzOA#R3fN@|0eubC$ z9yK@&W~sY4$eNADotA|FT)I>ZOO;a;{qKdfPGI|qIPNt2kY`lptd4Zg&qi*fdx*(5 zq*@pBzzQYXPv27u{5GaZNW*N09(H1@t!Tgr+z+Pwe&t#U3)!fNQv!SPuMUdgwps_z z9!<3AK(qmgcUuSa=4Vg9AZ8{%@BGm6kfmj_S8#@wlRPUiodAO)*4}CRAA~{yu<=w}vIH2Eqen z8-E5&BheFLTHv5OL>7ao-tLJ>6bZDtr~8+K-!-*c8Y%JSAefs~ zk|quj5;AMH)@tOygK~KT{G|<2r%ldolkL%QO5&leE8rL?AsuA=+F?ZY(g>viU|XF^ zSfDb??p+s5isg{&r;y1;n|+El8xW%mhl7e}qT!x>ZAuK$PU_m)+Q=@+U$s>m-22sV zpN2S+P8XNW#GrL${UvkJ4$v00T3ILp5QCuokRLfJuL`k~?_y+uU9r7c{}qq5fst7m z5v;t0&GI2&HOcIZ!4>o+O_Viy__rf<&YBu4m2w4cB~}zU)Wb)q%ucYIu|CSAARfB8 zwvV5e{61TxIb)8`J)wBXl3zNu+iHcbp##Ps#kMSXix8-B5=i3HeNyAn5CiZU$p{Gh z6z-?Oy#Ze@=`s96A4GnTwPj)^4c^9^|9jeNX?DX2C=HY?@itU@I;~D-CdZZETk!z2 zRdw)l90y&KCPE?fF@!Ec;2#&Og<@dePTJ-U@ROn%!RgR2S@e`4P|~&CexrRHleR*i zkRVHus0oi#giD_Q$W;b$lkYHqI3BtRBGaSqw;Qc^kng?dtPlgZ)2%1qAvrkQ@@IOv_0XJe@&tB`aDCA^LGS^% zQVY3!tWD=*7KB7ChOb|C@ERDf1gg`Jtv;-+Y6<~18Copuj!)9W%>QCT{LEz@XhZ}E zjhJK9k$xUzNgug96&-w z7XoY(P$e;gzBCX%v2qh6NBT{4e-RQw6O*te#x#4BCoDOss1-WoBSFdeoLLA?fXT-_scl?BAR}*KbwS z^j-10T_tgi%Is66pMg)jM^e@NqoC67%UieK|MZ*tbME!0o$@bFv@R&X$#<%$azP-> z@H_$cX%O-yR&dKVpdHcN*;$0J6WcK!EL6V;ub$S;=3MQyyR6z!n0bnC!c%P_UA(7A zAXomf43EN5^Q@x*Z3fzZLtr}){oft;7zRB{P-MWz`J}(HOk}nQ4?u>oTB;5N!jzOSJ=OE`x z7}IBvGyzONq=e|y{^}}eK~$&Kf;j7LCs*?b4BKGIiz0o%ngRD_Ey?|(t;v^Qp&ei8 zyi{zoFRKbH4){SBw4w0Aw|T8ikIy?SkEYHJsSy1}QIxh2Oyq~(pzg~PR3V+HlvJD) z1(7nR%jSl=fhvFpc?%IPCHEd`94LNXodKRP|GQ;3ag!PTL zHkXY!nL3p2eP^?{AB}AtM-;xjq_Fd|5ZyMrf#3+6Y)ayQ{qB0SdJQkAPVHpiD2Pp2@GFAT^)ij{CaZUuR1>jpaQl`CFv`otZnW zkRthOVi5HVb-7vpEkvML`T+ZXwE&olFuHDk`BI39oPxtljd)LDb2f>Rj0p`=fxUh^ zLt2mq3qZpW=;w0XH!$Bs&!1l#1+S-7W$5j@7e-|wND%J9JbMB4BB{{dzzBvE4_h$E z{BFyJvAFra-;<)l@dh$H4Ls(?V=V2{12qg7>-(L2SR3sOge$)a7!(4mFvNFK0wrM+ zt+H!BzTA)I67DXz6ffNx58PD;R(mo8&(^whF6*o<&QTHT$rt)DurRP7GHLekPX zI0Thn^3mpA-@ygEGNeHnpFr~7to(89;CaD{BMH$n$K%I(zm2O-F%o%DI6(^U1tPu= zM)ZOkCoqU62mV4SA1dOZ#iXUm2}hu@StOPrNU=kLtFa~1*(hm3)FVmamvn(b9WU6` zPWy%k_DK`Zfo$oJu5?vK@}ziR#vN3)UwHYw08TEhtKjl80G2~22!oZhPA-8#7*w)a z4llKGTo64cc-`g|lao@?1atN!>>-kk-&w3~vWU9Kqzzs-wy49{Wc@aZd}e#OQGk z6w2p+06r#@a76iY>m(Slm0UTtzu?>{0u7xT41$!;#nW;SgSfYr8x>*f^+7h)-9Nx< z_M49a;5I>m;)Oghz^E1=DSYX*%xyKSvJmHKpg%)V-iWA2iSHcUC|C0sC#TB^dSVcW zRG~@%+4rO!1Lp31T#$3<9wWQrUO}gCOz%sXMy7_ENUaezXT~~$s+x{MH6)zK0~n2| z8>kIil!M{MTjGRE{%5slB8Gl06g~f3X?L;%DU>&72C^-%Ci49pqiWtUzt{3-qI1)U z<6)p2Td>2=K+nVU<`t#v^Vbs43~0HS@@FX-WV!T75SV|$LpEu`gO^AAGUT8#!sA1O z=slA3K@MhwQG91ZSJt>J^hSuxHtOKlse^zz$Gz6u2>vT}m}{br^f}jbW6BnCJrSSr zJT0Uocoi7q5*A*{r|eM8&Uq=gXB{OG6bx*Gp{e*Ap@nE zr>AX&y{t=M5)5qh+g!+Ie%M5Op@@R@kAi~VdGsaYz1H7zM(>QqWKg{ByBKE-osg&~ zGuXmaf&`jiD>~+snvjr?I?0Iyi?t%^%`w4Eb6p_aUkiSZAjm*iul#X~$;saR&(X2o z*xsv5PMS#*1P55qA+(_9Z~*~JdaPfOp#c`_wMsy&Rz%@AirRfE8zWmj1JS&WfWbk7 zBG=m5ZY(~){<_{TX>OU#mHprkAhy59;7>Q7 z48sS=iYLfLp4PVp7nECUc=zgGiJO2X0yaVTx;fBhrXO$Vy=B^|4;Bl+1At zS@VH?DeQlbH8k-I;43ykb!&HWegyio|fOMM`eUz)w6^GufFDx2^XyC#V2bN zq}8@+qd=s04;rCJ9w2h9SC_GnaAZd?9c9v#+ib*@$L)xJXc7PRqjc+W<~P_&9GTwm z26~Tz?6c25{0>!Xo6{0ilUE&-hu)4ELx;@pduskdplL9h)ex~S9$~b zT-WX8l~0n24AbJQqt^9qZ&IqJGn{>XJ8q-r}|-eT8b}S!N963ykIHAlhe4B zRo`xBqb6UcdXQ7+_0iOEdKKa?B)-deNJV;=_oUDA$3eOuaI~)^UI?`7eF?xE3ZRXo zn*ZR-*5mya9PW6pf8nm-2Vr7-lUU~xW;*s@Iqu`-g0bI($bB%S^SzjgBT=mk}7LM~{D!{p30pfT{& z&|SPi`nk(*&0%XsUrVA*@;}B;aY5Pf<82pAH-AMZgH|&`fg7BM|@uCIhaPZLbz|K7vFt1 z=O}z$;59UDB95XNq~b7;QkCd`~DCe1r*g3y5(IjG>IJP#cBtb`}0lS4Tr6iN)Q z0-H;FtQC2CYuag6`T@r#qHDG%U(|b0Yzb(~%0m~dR(Q|h3PZxe`l|(wn6g}tAn#`# z9YKB*a_cWW>D$YnjD!bD>{8So1f2h6bbMk2n#6JMAE{>{^@5EfV?ZEa2Bcuq9h_v} zJ8J&>g@uLZz{lN~O}puR!S0jy1t#o!`QOmk2fTqeE0aXVEPoCJm%MvUWG4Iq`QK&$ zKtw?b&!2!z60MP^_XTVM8PK7b2h5_H1vlCSXA1qx%sPPhz%#_gCjuQYvlEDr`mCT9 z7xKlf!!V6LyHYC~G}I_>$fHMrpYbaP0bl9Ddy@Pu6kcAv$6W_|0|~mH>AoY~Z)lFP zBLLMpK)kXKB~SMN{zR3@BiM0fOA4Lr&j;$~xGT;<5C~IwM{9tYDM3^(XjcubQ3}|> zBgT1pBMIgATCSHl+N~}h}-p=J*I7=0=H!l!Vij7J_c&wJlA+FO~@`uvYlp~-IgvGwm~i!5rMJ} zo_EUcDN79V&O^3%I11K%-u?eo_1*DYu5tgjoOGO~bV>;gk)yK8%&44Xcj!nG%4iT- zk=-e)LdPbngdCfYtrE#BGO{XrWbgTVU*GC^p5K4Ha)0mp8lU<8tWiBFQPJS4O3iE3 zsjF}X5$y~TzjNsA#Ny`)ooPYcU(Sc!_b$4=k*c*W{OechK+H)5U>AZ`#&wsE4>08F zlXEM%>&oEb4{s97Pi!{Xk$1)(Q zY9+l+?nS4bfpsp0LQ+!fZb9AFD1Loi@#Ycnc_+6?hv8RMe9~JlqQPiBsH6soI3SKV ze3}=qQF2aCD6Z>$Ny%Nl+JkBly-sdxs6c<_bgI}F$xxhogyV+yr~jYp9yV9ls&^Hf zfOx0?PEXwRklj>*uHz{14)|1CngWm3$PxLt^agfY>QirLdwXGIACYcT@yvaKaRzjO zrL(gyz8ID(D=W8Mw9UDah0ESYxaesuA&kg{*4}mpw0e?^m*`{1^SL$sP0OPr%WXyW zumUy{pqZNY0aHKx$IP7X126(-MAe6LdqRz$kQgSlKL%O?-88rP#12R0kybLjd@JL8 z?hq%fXTF0)GAji91Hh#Hl+~%#%ZEWTlCR;YDPz z^SkfC=gG$hD!BGux&X4wTUlPnE?AyQDdMzV)0T;-2MY-=(w*J`kCV)O#PN0v5q79t z2)dv30jGj>v#z4zn_g)@m7b55w!4L|n_+S?%{`-!+5)mR`SiS8Bxj)*8dC-QYbmvr zI#o)3DjR4R;34`jH@Xk43i5l=-tH(jzH1G8#^DOeys}&3)v4c-kPd-n;REXeixDIk z=>X6qt=#t4jYeXbim#&jR0$(;!iDzqI0)5O-J-H|k&tuOQzYBG0Z1>BKg67okuk%f zbMr2T6y<`D37w1oqME_KQY0L8Euwdgx=pPk(n|#d1R%7c9s-OuX?-DJ&7j!jhe(S$ z98A6Ms5#5~LZgu^5lnCivIkAUgE*toa}SPPfq&-WEZ z%lRz#-Gvb%f&qyRf7DE*0j-l+Nk<|j?KO$IMazqD<-#%1x|_sZ7-TLgsi?SpF%20u;wU$;A<%7xpRT7mFUaxo^v0FZjUA!l zPkssWSxxy8ouVe>+3$iGLmePEhQR9D+S7-3ctOBPUNqspzsDCCuU0a4xO7N{*W`Z zYl)nJPSNo6xGB4iQ-vp=pc`_0_RSU5%55({goKBC!L$<+5&~V=z3S>RNIc)0dZGx4 z7;W{s%iX#gU{&2Vo;YfA93)mvNQ`*C7uRO&UG7p{?lOZr_?%=Ld>2=Ya1h*r9Q$CV z&L)2`ESnA4i3|c_)ufD8_-=TCmS%^_5wOJxV=&9ZZ2sGYBI4pZSVc^g!jG*wd%-$D z=$G)cH*=a))LBu`#N-2H`n=lS{3lYeE0T)FSc}qxt=A}yd@@e)@?<>Q;j*lr@bMCg z(sFG07HSZIo({A6Am96Rc)urHDiI=RWShvTDekqF*$$KN%c4gx*>@g>;px*Xv0`7~ z>d3%&J(@16;&#@0tkvVWs z!?jGcILfNc@^!`I-8CH3(LV`Oll_pb)hh(8+uDtwm8BNxj%?tU?hYeL)8&4N1`3D#wZgS4pG zJS?rRKT|(A6&w;GkDp^~#omS#-AM5}vL?DW>k%0E2(F;`49Gr?6fU*xCP@Pc@vNsV zLllHo8Ii$6JQSOVl$5D$b1#15A6Z1_5}{9?7lYk<^6m_)MDbQGlH*5E%Iy>z5WyWH zZC2_7>o%u5HkiIR{0;GH zcyX%`+hhcvd-%o=8nS9!5HfEyQ z_Se?4+U9QtJDakH`Yo|%KlOB(i!3_h$Fuk(O!vTCFIJ>Io(N20@7LIRHbZmN4Vs?A ztft(0wn>IZ2qg*Sce&zRiCW2|-38HlwHY9UyGbv-Z_&tLw9&8A^NsSk1=Y^`MedsIpR2BfejUCcT~`5da*DLUW^K0pEtgHyyz6>mXth z^;s9PwI5qqgb%9d%`Q0~jkRpRTKEL=yWVI6-e9;Me&nhx_9;$WGkBcs2w=xcy!%R2 zv`?hoo!;$OP4TGjwh5>YhZ$boxp$u+hdS5(L&?-wLJsuZ`UwE;6C_b~c8BH)otvfu zo9rsSdmT=3j0YrNE9$(HXdm;oH!WJ4CI;=l-{3tHc33=0)JsGVA|J9!kdgo1CaLu{ zao$lgB(D|zW?$ zTpOKb+V&|Q%G&vewOsk^tsT_%WHQ_U>uGD*Z@_dP4vj^eeX=GsASrdv*ov zG{NcOyPcKwK8pLH-3pAS(QaLOwlCVpE+sDmu?Ik6bVyStTi!F4G`7LMF|U0pmx!Tb zX6Pk#50n^iZ>^I|@8KQmUn@GrsycjSR(@UK-C}@C+TuyL|1=V5PL|w& zY_Mw_8ZrUSw4_WtF#h5wMLbvaLV^P5!SwtX)9AOM{1umE}kzhhAl2Nj+UwbHpC0|Cqx#Qq)ni zC;SLp^dn?D4z%rD5!_>>F6Uo`Lf@uP$5@* zIDhE38a|40B~o$!(*qTydoSq^c&E>`&lG0&lL@Qy^=w;SL$G2mClfv@gs+;!5P{8b zrPG`WR>Uuw(wGXS$HiN=3+Z+LhyCV=`LQLy%+KZ}$$?23E!}U40?aK{MnZ4^peH1e zbaXPK`Eb604jFgb%H|f-RtqGbx<|4F_do3{deBUcgWYlRy=4kg0P@sqPVYp5Ah8o^ znGvfvHBuUpZTki`$H11~y8e}8ziRsFdB2FdjlVzNA|2)0efI!$TJxs>R71CcS{oP| z1|z2h_|PuO2XZ_(ByEUp$q3LCNpr2=zNKbp4*e2}@*SIh|LIVqo+kAA>fJ;>TNZ!b z*RS{ayhW!?H&-@8>5&A@kJoUv`_$skAWHUO)OU3bx)LD)XDDEK8O03UUiG_&p@~Z30>bkg;nDJL$ssQh9V>`OpH-I z0b;|rB3Lc7CkuQSjanC7=SC>|o3P)5$sU5k!XBUliumfjf8bk_RN^oD)?(Cj(6WRHHDGDmnO;L)_94L~Z;o^nr~<{bOf~9q5O`F`%wv+GWY6{Rt?@_$O z{=&z!bW{Oh;Xv`#!O=KkP$12d(B_g#VpM;8E@!3uH)Vc`-`AdIzx{5A|^>O}pBTj~3P72%=>9BaAc6j3q`rVqFn}dUcJFpBAf=cC;-ZEZpJHE32oM{ zC-N}H->~_Vtcgn7Uq(P$mn|~2mbT$GQ?PUvs276$tX7CYHUuaF4bkIN9=FC~4#!yV zw~FM@cN4A6IDQ(e5aUlIG_hceNOD~Y0c_>So3JCI?O>~m^R8t>FaSjcdoYUrqOE)* zI!!v&jHVBk61T|eKG~EJZswf{GEuj|4*I=AzU|l?Ci#)$M{cnw@7lGP{=5~5(%(sI z@;1pr5Hb59jasJ>uS4+xjIpBei#_Awbno+-DGVwdr zqmaVLwp=aL5w#t2r{JtUBCIn>V;za*3O2KgHyeu)FrV~;K4v?V)l9gGGmChccjB~1O@7I8DaZIG(r*`8>@NgSaoIB=5R+fs2#H`mW z5d$0F2IJN3@+;K%and90Y=ez?163b@Eq%Tobm3-*4PTzweX=ADTVlGcJr{Un&nq*l zJmZ_lMe0EGGb7~`mi4L7(H@j9m(i>gzDn^4qyq3blrO(QCD6dm`Nl~!m1b`#a$Z>- ze`3D)N7)sXOEV(*u++)hw{_L zA#Z{pJ~i)3q>~w(4t6G1=$1CapbOL8WSD!9+}(~?zc4SQcd-Z__VqpUQnV{Yrd>uq zbi~c>Cks%BB(HmNEwL`~2I6_LBwDu}%x)cbC9|XG<0U?eF@$Wnkg4T0HfBC@{)0NO z3WqYxPZ?kPszyWc%ly%rGGZqlAZ2_}DF8wQGf+XX(nDa94#YM24ogb1foNdwsKphB z;i@oO>Bx(x+o}qCj-)itjlSMkbkO<~2LjhXB7_i4r2-$87|WIDLCQ&><*JPo z1W3)vlG6iQXRp@P)e-Xv9ARX%C>7i;gem}ieSI1ly;`Rpoq7xU5xPh$pa0PG5b}+f zA8I7}Fs~A5xR)tS%vw&`mXKK{qW#Nuq6g)CLg8GayaJlr=Vo5GxVzNZ_%jjC9Tqog zXH5DobSzJ2OG~0;5egm9dqFw=9``Re_}vXJh4$74_2g)c{By*M(b*0x=SRD zF?GXp>9^{mE@tkc5wYt|_*m=-6ug?f?M}xr{)NKH{kZQ@M}#86I8=ZOrc} zLmuO3i<RPZ9uSffj!BXbKmNP6;zF-JVU7 zUV~oCi_aG$$qiZpw(9fnb22sIZb`6cuvdEe2)d_>G=wh*oe!mNj5}Wa={(Eukvt4h zfLz~CK2jS7nC^0^NTK;H*gT?QY`=ip>eY|KxY!RYCRK2sx~bFCfcQ_-NmGhR}XwiS@b%AoJJF z{lbt|mnhKi#weP*a7dnCPnw_~605B+H8Nw%qq zTHPIGD&^wgSes6F`Lv$gUms?P&_U5AbrDj#TCwfJb5QIDPZyA>G)(x$(gc7F1l5j%q=xDWrO?9 z37mfF^Xu+_4yTCThz1F_s(nG)W;U#^C5torcb1MjhkA&!NQkZUz_q}1}k zgIOo$7n_K<>Fs+TJ(JZga93PDt5M5+LPC|I+V4WQj4~+jSTcPOZbL+d!x7a&$v(`f zsTX^Cdo!LtpZxFH+^6E4)YONruCD9bpyZa{_3|DQEa&Cs@%z<3^(DL0>=)@Av}-pt zF3>;Krez#{O%kTlHbx{Tn??BxMszvjqYof~7Ic>0P^9nks zsVCV`#k*(?>PT)&(V?$~ywd8%7p{;6oTV+`iN9c|!S2ErjU^Cou6qgOi9Y2UC>Bn> zqQ&uOV$gjw|J#Xora^0CCOaKfTk#7@P$IGJf4kCf$Y*+q9$hLL=Pj}@8{AFt|LTO8 zxAc;_^pyGvAHFw{*$|!tCtTWc9Xqsl65j|e=~s%^a!z(82G9TGM%{AMRqcbG$NA&uyiU)qhu_l~0zMvp-=|kyTxaba<9*k6POa}5fdNI-4QGIat2@`?x#|+B$Bi*BIB zgx+CV6f)5Z6qL%4+2HzOIUyeS#zG@8 zZ&mk&m=&z1>@;Z)bHHS7Z#dx=mY`2ZRo@}MIGNe-THfgV2#XQgmKR>dCObUHMyxs< zXB>6%hZy}T%;3qSGPDyhxG~26J?C2alRH$mUn6xKlc+>{Aztp?a2^*;`ja`6aRhA* zc57}$HQ1$+b9Leb-Gs%dy_5AV(;8v9xrd7i+pRPG;0>olIB;N5=~dw9)%#B_e`3!dW5?|8pMWKoE;vLzF&TmAupxjwZyh2-7)>IUS-{ z)GEftlN%&X`L^=nK(tx7QC@TCVS<5unLFa`(h?YxX>Gol*=4tdM*if2uKoXzj07PW zHh;AZ+;g&nY@8A|hh|4CEiKQMJ_@GR(T%0|=BG4>H`1^{*??OiqJO5D_jTv;WGfi%%u zk*zzw`BA60Gla_qqpP4PP&~lZ-z19nXOsn{m?au;H&>xaJaj zbf*1Pd_4(SF?ceA3I`K^kd>8~Cu1?yKh#mQvJCfp-Yvd8J-b1?4GS;cWlrd5NjY{Q ze0GxJ7NBF<^wrSJP6kG?rn3sxXyWqYhCV+~Je1SbPx@izWEXt9-k9CKiZbTZnU0;~ z?96P4X*huo(}?Yu0*||&!;`5EI)=+@q-S4>9Lnu`@ieD)tM<#t3dP{j-uu4s_W1-jdp6N4?pO_1Ijk6BG$e3|Cln^cBz zB#=yfgt4u)k98!p_qHigE?&K8G*{ds8f;KF^{dWhT=(4DID!^9Yfr6}(I?6IE2ogB zWpgixq8`0w#JZH#6q-W}xK!q+p3*uGPXa=95-q&4PKG{CB|Nv6bkgKqc0QgWu3;Q* z0*R@oNo32TXa0gAT~`L#!diZ+gD?j=Jt1o+bg`XzOfyr$Z;gbi3hEeNxJFL)`_B^n zEkw(?wMIU-I+4mtPZApmzmJ=V1&^}W-iHQqo~3CZ_E)R}Pg(gcu&t$1J;@0Y^<(}n zC8%np4$WG03p?3HUKBv~F*Gc~=_@p!pS;?^U)N%ql&L~QG`~sv2Rn)?ez-$*Mq<8S zS%TDAv|If+cD>PjGnP*Q z7r@^UsxeW0_!jZMjOA};vcLYXvQdkh z97t5f@97j$U4KwXqPL9zov3@j%%Kql!4G!p64HYWddHJkpb#mti!%Qo`%e&F`DW(4 z;GDnEHnO}CDzUcJlay7&UD)1oR$RW+7<+d|t-Bl1Say};Q-&EyHmTPnNXS|ONd*>{ z^Y1hAKNkfe)(;G3- zvAAq$GS`49XLb*X#FM->C!XQiAfcIY0U%y>p4wKu)PuU)S;x}(s_v6xRVK%JF|#3r zGdrvOWoQl_xDoDXIF#I=ubBZcMs9bsM;icP?V6uLtolB$AsvG|ul~Y$?(*63gWGU) z{6vM!%Op+d`RXUx+yF$0Z8)KTFVFWt7CU|M94NkUfC_JV9y(PJS1UW^{TVdp4rDZOCV3)@MYX+*a?m2Ccy}LK<1*S zYKDz7Xr`H18waU;6>bce&>ck7%|q+EhGAuaX7K$Tr%wy2Z4eoUP!V&RBkZHrk#3$4D2I_#YV1>>yiw5 zZ>>oXFHeCG#%+F%6QCs7fi9%#8`aYcJ;fT2J-rFXPbFF-ElPC8vH;S?aLq1*dI0@f9Kj z*Re2JMpa4Ae!ioQY_ZYRwk{w0t;ECKfhlB{oPU2u0eYE5hFC__W`Q;B^ooj#(mS_r zH($M{nDtQ``k!vYoU{JlhF|Uj^R0W9{hS?wcs?QX(7x@ef*rQMv34>O&KLnE(m}hL zsImi6V}y{O+<{FaoR`q=y9cM+u5NvMZD**{&VZP4J)N;+B)a#F;3LL?mVn3m4o z9V}AG_u1Hq!My1P(YG!Mnbk4&;U;loTZC&-5#qcso|(SFQ|{SdPYIWQ#i%yt3hOj9 zfy4GU6SHI;Be#J2yCGy_i#meu$~h&peCV2}aAM#_5}xSr>k4epZ`wlp1{3z;=HVe` z<&6SbbyZ!NVq4;WJKlxOe>V{_!636X?gzCYjoV%PE&ZEG@X5ESNkAyw`LqUfhBg^Mgj zfXVV%l@utV4is_Y31i=p`y@%8gUsV~$LH7d4DHJTn%Oc@7$W z+sX~7;h=qDEMI(uei{@qBjo->xtaV#`0Y{r#j!FOC%sf5Z+cadq3`MhIgK&nl!ECC z@?3kh$FJeWDYH{p{pa-uhSA~RKH`F1N94KoC{dRyBaYr0e~hlVi`N{Y z>3hkBM`K~@P)<+O-kot^3bj0+j~iVcC0X-^{Sm11{Gw?lE)fM;LO>)|d6X z&tqD&WZu?*#XYnpVC$+rgcR+^P}zVou*C zO8-}*)-I6mY9#qv>@Sy0vZu`F_T0=2jfECLEt;Mz_Z;(ehKB zJd^HkI7!)ly&{oga)dsA)%3&vq1wiN`3tEA(p=nOGzAi*s%e*XizjACNsyVzFHFTa6UxnUbY?Jg5pI|br8ubpl%6)68g zgl7`@C?E0ZcI_%3PpQHk7~d7XB0*7{M z01@7l+vz?f7-?_~N$k?W5fOz_PS?|<{`V&NS;$Q`{LN!1SpL32f@ME9;;#SsA?Sl% zjTL2Im8CQj-f-5f)N{mzS z?MLc)%2D`B+u{~fB6<0~v{riuawv&t+35yO2|qH;*Cs~3%ga6Fr@Iw+B>XC6OAPe$ zg^g57%9S=9Y*s3}mgGka8~$LjJYgj`scjzp{ySOY{S4-jS++Fc$F1sZE9AFZDAM%# z;`#T!%2vin*8dS^We6h7>Zau#?Cu9EdF_c#S>JvDO&lm&a};e~&>syuC76N!avVyk zsw--~V;+Gf-YU6gORJx=Lucy|x43CbjQ<^ZsYbgsCobbOQF3ZC4+G!MELWh;Q*XZN zl5fbHH*cgnAduc>)JWw?v|Zt;%n0f6Q)VGco?*{U?=lJ>oK(@gzz|JKE6_=zN`5 zNGDU%Reh=Q%5p#MqFj_XWXG`{DC_Ky`(*zEqoCYq$EdTqpKnu#rMH0Q0138UUB&i4O+xlrSxWr)IF@OAm-l%Oz`tg z9oEC)wOz-nVp$IqS!<;3^r`EcjD5q&+@ALfWRtVcSWH0oO;49@0VP4o-!3$P?T99EVqk!kOZT$iq13odPm3-Uz+ zPwfXR;MAjw2q82(C7y0Q-S2dEQ=(IX|oHYL(9OV1wOl zECn~Pr|e-M#Y2%IX}-q#6-=eiOM9AE-TW*B6FsHejqc?r$A3hw?PW={7wdZ<83m2pPQrG#Z_}(F?1E7u1 z+O$oD@)~~mTjQVB%5fjs1udY^FbqgjQLyO)#p*D2?Ky{sDi+DI?Om1qR-z9dnUe(b*#}` zf3|cLRlAM6dj220`b0P{f3kL7?!ToqW4+p5YX?*OhT|*x$+q;4(4KlX9+2+7=LS`L zt&%(BS>_?ay;Q;!4f)hNcrD4jPBQZd>_=)c*WNfu;tf>8Ji&ToI^totu?lcpISMfG z{UzUx9|=y2ANRf{e&}Q-m^Rl;KUZxl<;&b(Xp{5atO~bWA!JW6T=qUyb9>dGN@uFUg z#dV{Irpg5gt8xNC^Sb5U#+~L z3<&yzyu~wu4uXNM$m8WMoH72MRwrWNXFR{Lr%gRbk+6h}vDsBg^hUBfmSinnKFwLS zLzPbN#R0Cl(@ECHVII32!i%ZEk6J+x`|?u$28ClgDTa;$`I`;j?GzWCufJj9t}T6x z{|WgGrJ3neVoEdTnjikX3?EtbXJvo2EN-!|uF@<;iiHZddfiPscpCanX}YStv-OSV z)W44TG;!>wEZ#~$-;eqcDV@rY9I#r?OM4rfa$|z<7VijvMOdIQ9SEGM@7(=^hbp-pT^3E&Y50F9LIN*jV*JZ-0y6@1ZY^n69XZ-WO;YnA zxC?4fZ%(WE&X^QeF@LDCh&D~(PqE$9Z$x;<*k4Gz zfv>X;(LmW^{%4sgAGNZ%bB?r$)KPsK%X}A=lC0IpMO1x(6H1w+6P)Ny1;<{mUh0Nv zhCG*X(s$XGO03!_rrpd@+*Mp+XN<$IlFhjVkj;59hES5nUf?b4#3qpO*(698y6F&} zFC)iRtAAI?MR~V2`3qTOlpLOCJx+U`oA$f}uYn5JcH=yTC^I%i!F}Y(5u%Kve6StA zo%bFxrfQXakTlP!C00+WI60-s$K4Na@e_1{vipm>{EYAGS0MCB4nk1#@C1*xF^A-R zIz-pUcwdb9P|yxDIQ`XrWV!TF{$S&Ww-oDkQ`Zl~+A9yy$fekod{WPa_yh%7(|W%D zmReH6pGfgI3R1cv?kwTaoK5?xFqa*Mquz5+O8->aCX-4CqQVzVuTO z^Oppw8nP>i7>NfkJ_j>it)R(vm&faFz)_|bl9xSp<|ZMEU7qS8GD0fnAx=_=Wksb} zG{jeWa_TFWQFkg^0`WC5Lhi+^f5a#~wf|$Hv{c>YWomHO4d1JA2QgJ%g!U`xzlgE* zP%Okiu1-LvsGl=LW#(Q}PJ=#0xwMmuqKv=ZJEs?*%>;G{+eQvr)C>lT7_*SvjvBg8 zkCX)ihJQ~}^vVXuJ1T&-sfIV>_946+m$=sX%!PRduDu?IKhemZY6uTzq*r}Tq}2m* zD<=B|m>Jxzkbe<9N;Mt6{HAgYY}-gB+}KmDBn$q~VVa7-0xnL7XgnH9ySf%eg zQ0En>c)b_zeob5{DwH?Iq$b2KL?o+q)rl(tZF*wr#^I)t4EQbivz-EMqy7J#YZA>6 zV?NjmZybAhM3yo6ygR|DtZsd1-lyc-g;Vc%Dy*Vo5-#G9B1q_va*RO`QYcQSAe^!H z=JfeMA;6xo#`tmr?bY)Q=NhY$9exd6mk^*Q#@zUd{6vL(l)){kd=t|Fyy!OVMf8J- zQ90w@u_A~2&))AZeV6kqxhEGwgD#KL7u|XkYFk4L61&-L=`+rG2gvv2U&Qj(F_W`l zxz;NhlOt4q>b3m3$T=(hn7RP0fN&_K6GtO%o@?pt)!qS?Ko7Gl@i#jkvbogXD!7lF z{ikQTyT;~ln5@}gSLN@iYx_$TxG~s_(jYi4^#ZwWxYEOCrM3yXmnl38tFU;cB%*OB zbLVQXat)z3m-VR*>%UD~shT8*wZqm*e9w8P(!@6=j4@zsvNIlQVj&z_%ynKWGiUP= z-G%6E;g;Z<5Sh9EIKpG`jV5jKcNrfs-W#U6%cpX=#hBwnYswVDv>E;6XRg1Kjlx5H zVzh@M|A=`IIpu!Yxp1>g#$xBLg7Td4p00bY-9C+u2pT{hP>ynB;VgnFjFG(6-VwbP x$wilwwpwuUCr_vFebnmJS&_z~^iD51r Date: Mon, 18 May 2026 14:30:45 +0200 Subject: [PATCH 55/86] Refactor `download-native-binaries` action for cleaner syntax and improved `current-runner-only` support --- .../download-native-binaries/action.yml | 104 ++++++++++-------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 67301cddc..6f4b8d860 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -31,32 +31,16 @@ runs: arch="$RUNNER_ARCH" case "$os" in - Windows) - lib="windows" - ;; - Linux) - lib="linux" - ;; - macOS) - lib="osx" - ;; - *) - echo "Unsupported OS: $os" - exit 1 - ;; + Windows) lib="windows" ;; + Linux) lib="linux" ;; + macOS) lib="osx" ;; + *) echo "Unsupported OS: $os"; exit 1 ;; esac case "$arch" in - X64|x64) - arch="x64" - ;; - ARM64|arm64) - arch="arm64" - ;; - *) - echo "Unsupported arch: $arch" - exit 1 - ;; + X64|x64) arch="x64" ;; + ARM64|arm64) arch="arm64" ;; + *) echo "Unsupported arch: $arch"; exit 1 ;; esac echo "lib=$lib" >> "$GITHUB_OUTPUT" @@ -94,16 +78,9 @@ runs: echo "artifact_name=$artifact_name" >> "$GITHUB_OUTPUT" else case "$artifact_type" in - testing) - pattern="native-testing-*" - ;; - release) - pattern="native-*" - ;; - *) - echo "Unsupported artifact-type: $artifact_type" - exit 1 - ;; + testing) pattern="native-testing-*" ;; + release) pattern="native-*" ;; + *) echo "Unsupported artifact-type: $artifact_type"; exit 1 ;; esac echo "mode=pattern" >> "$GITHUB_OUTPUT" @@ -121,7 +98,7 @@ runs: echo "root=$root" >> "$GITHUB_OUTPUT" - - name: Download Native Build Artifacts (current runner only) + - name: Download Native Build Artifacts (single) if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'name' }} uses: actions/download-artifact@v8 with: @@ -129,7 +106,7 @@ runs: path: artifacts/native - - name: Download Native Build Artifacts (all platforms) + - name: Download Native Build Artifacts (all) if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'pattern' }} uses: actions/download-artifact@v8 with: @@ -144,6 +121,7 @@ runs: ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" artifact_type="${{ inputs.artifact-type }}" + current_only="${{ inputs.current-runner-only }}" mkdir -p "$ROOT/windows/x64/Release" "$ROOT/windows/arm64/Release" mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release" @@ -153,25 +131,44 @@ runs: src_name="$1" dest_dir="$2" src="artifacts/native/$src_name" + if [ -d "$src" ]; then cp -R "$src"/. "$dest_dir"/ fi } if [ "$artifact_type" = "testing" ]; then + + if [ "$current_only" = "true" ]; then + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + copy_artifact "native-testing-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" + else copy_artifact "native-testing-windows-x64" "$ROOT/windows/x64/Release" copy_artifact "native-testing-windows-arm64" "$ROOT/windows/arm64/Release" copy_artifact "native-testing-linux-x64" "$ROOT/linux/x64/Release" copy_artifact "native-testing-linux-arm64" "$ROOT/linux/arm64/Release" copy_artifact "native-testing-osx-x64" "$ROOT/osx/x64/Release" copy_artifact "native-testing-osx-arm64" "$ROOT/osx/arm64/Release" + fi + else + + if [ "$current_only" = "true" ]; then + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + copy_artifact "native-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" + else copy_artifact "native-windows-x64" "$ROOT/windows/x64/Release" copy_artifact "native-windows-arm64" "$ROOT/windows/arm64/Release" copy_artifact "native-linux-x64" "$ROOT/linux/x64/Release" copy_artifact "native-linux-arm64" "$ROOT/linux/arm64/Release" copy_artifact "native-osx-x64" "$ROOT/osx/x64/Release" copy_artifact "native-osx-arm64" "$ROOT/osx/arm64/Release" + fi + fi @@ -181,17 +178,34 @@ runs: set -euo pipefail ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" + current_only="${{ inputs.current-runner-only }}" + + if [ "$current_only" = "true" ]; then - EXPECTED=( - "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" - "$ROOT/windows/x64/Release/WebView2Loader.dll" - "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" - "$ROOT/windows/arm64/Release/WebView2Loader.dll" - "$ROOT/linux/x64/Release/InfiniFrame.Native.so" - "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" - "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" - "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" - ) + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + EXPECTED=( + "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" + "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" + "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" + "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" + ) + + else + + EXPECTED=( + "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" + "$ROOT/windows/x64/Release/WebView2Loader.dll" + "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" + "$ROOT/windows/arm64/Release/WebView2Loader.dll" + "$ROOT/linux/x64/Release/InfiniFrame.Native.so" + "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" + "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" + "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" + ) + + fi missing=0 for file in "${EXPECTED[@]}"; do From 611dc816b19d7d28f68e71bd07a58e12ad0735ed Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 14:40:38 +0200 Subject: [PATCH 56/86] Simplify artifact copy logic in `download-native-binaries` action by replacing `copy_artifact` with `copy_flat`. --- .../download-native-binaries/action.yml | 55 ++++++++----------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 6f4b8d860..8ea888616 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -127,46 +127,39 @@ runs: mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release" mkdir -p "$ROOT/osx/x64/Release" "$ROOT/osx/arm64/Release" - copy_artifact() { - src_name="$1" - dest_dir="$2" - src="artifacts/native/$src_name" - - if [ -d "$src" ]; then - cp -R "$src"/. "$dest_dir"/ - fi + copy_flat() { + dest_dir="$1" + mkdir -p "$dest_dir" + cp -R artifacts/native/. "$dest_dir/" || true } + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + if [ "$artifact_type" = "testing" ]; then if [ "$current_only" = "true" ]; then - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - copy_artifact "native-testing-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" + copy_flat "$ROOT/${lib}/${arch}/Release" else - copy_artifact "native-testing-windows-x64" "$ROOT/windows/x64/Release" - copy_artifact "native-testing-windows-arm64" "$ROOT/windows/arm64/Release" - copy_artifact "native-testing-linux-x64" "$ROOT/linux/x64/Release" - copy_artifact "native-testing-linux-arm64" "$ROOT/linux/arm64/Release" - copy_artifact "native-testing-osx-x64" "$ROOT/osx/x64/Release" - copy_artifact "native-testing-osx-arm64" "$ROOT/osx/arm64/Release" + copy_flat "$ROOT/windows/x64/Release" + copy_flat "$ROOT/windows/arm64/Release" + copy_flat "$ROOT/linux/x64/Release" + copy_flat "$ROOT/linux/arm64/Release" + copy_flat "$ROOT/osx/x64/Release" + copy_flat "$ROOT/osx/arm64/Release" fi else if [ "$current_only" = "true" ]; then - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - copy_artifact "native-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" + copy_flat "$ROOT/${lib}/${arch}/Release" else - copy_artifact "native-windows-x64" "$ROOT/windows/x64/Release" - copy_artifact "native-windows-arm64" "$ROOT/windows/arm64/Release" - copy_artifact "native-linux-x64" "$ROOT/linux/x64/Release" - copy_artifact "native-linux-arm64" "$ROOT/linux/arm64/Release" - copy_artifact "native-osx-x64" "$ROOT/osx/x64/Release" - copy_artifact "native-osx-arm64" "$ROOT/osx/arm64/Release" + copy_flat "$ROOT/windows/x64/Release" + copy_flat "$ROOT/windows/arm64/Release" + copy_flat "$ROOT/linux/x64/Release" + copy_flat "$ROOT/linux/arm64/Release" + copy_flat "$ROOT/osx/x64/Release" + copy_flat "$ROOT/osx/arm64/Release" fi fi @@ -180,10 +173,10 @@ runs: ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" current_only="${{ inputs.current-runner-only }}" - if [ "$current_only" = "true" ]; then + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" + if [ "$current_only" = "true" ]; then EXPECTED=( "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" From f210f8e7962b1ea0a2d359174f70e9331c19c01f Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 14:50:01 +0200 Subject: [PATCH 57/86] Refactor `download-native-binaries` action to streamline artifact copy/verification logic and improve `current-runner-only` handling. --- .../download-native-binaries/action.yml | 99 +++++++++---------- 1 file changed, 47 insertions(+), 52 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 8ea888616..515f46429 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -123,6 +123,9 @@ runs: artifact_type="${{ inputs.artifact-type }}" current_only="${{ inputs.current-runner-only }}" + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + mkdir -p "$ROOT/windows/x64/Release" "$ROOT/windows/arm64/Release" mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release" mkdir -p "$ROOT/osx/x64/Release" "$ROOT/osx/arm64/Release" @@ -133,35 +136,15 @@ runs: cp -R artifacts/native/. "$dest_dir/" || true } - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - if [ "$artifact_type" = "testing" ]; then - - if [ "$current_only" = "true" ]; then - copy_flat "$ROOT/${lib}/${arch}/Release" - else - copy_flat "$ROOT/windows/x64/Release" - copy_flat "$ROOT/windows/arm64/Release" - copy_flat "$ROOT/linux/x64/Release" - copy_flat "$ROOT/linux/arm64/Release" - copy_flat "$ROOT/osx/x64/Release" - copy_flat "$ROOT/osx/arm64/Release" - fi - + if [ "$current_only" = "true" ]; then + copy_flat "$ROOT/${lib}/${arch}/Release" else - - if [ "$current_only" = "true" ]; then - copy_flat "$ROOT/${lib}/${arch}/Release" - else - copy_flat "$ROOT/windows/x64/Release" - copy_flat "$ROOT/windows/arm64/Release" - copy_flat "$ROOT/linux/x64/Release" - copy_flat "$ROOT/linux/arm64/Release" - copy_flat "$ROOT/osx/x64/Release" - copy_flat "$ROOT/osx/arm64/Release" - fi - + copy_flat "$ROOT/windows/x64/Release" + copy_flat "$ROOT/windows/arm64/Release" + copy_flat "$ROOT/linux/x64/Release" + copy_flat "$ROOT/linux/arm64/Release" + copy_flat "$ROOT/osx/x64/Release" + copy_flat "$ROOT/osx/arm64/Release" fi @@ -176,37 +159,49 @@ runs: lib="${{ steps.resolve-runner.outputs.lib }}" arch="${{ steps.resolve-runner.outputs.arch }}" + missing=0 + + check() { + if [ ! -f "$1" ]; then + echo "Missing native artifact: $1" + missing=$((missing+1)) + fi + } + if [ "$current_only" = "true" ]; then - EXPECTED=( - "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" - "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" - "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" - "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" - ) + case "$lib" in + windows) + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" + check "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" + ;; + linux) + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" + ;; + osx) + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" + ;; + *) + echo "Unsupported platform: $lib" + exit 1 + ;; + esac else - EXPECTED=( - "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" - "$ROOT/windows/x64/Release/WebView2Loader.dll" - "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" - "$ROOT/windows/arm64/Release/WebView2Loader.dll" - "$ROOT/linux/x64/Release/InfiniFrame.Native.so" - "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" - "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" - "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" - ) + check "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" + check "$ROOT/windows/x64/Release/WebView2Loader.dll" - fi + check "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" + check "$ROOT/windows/arm64/Release/WebView2Loader.dll" - missing=0 - for file in "${EXPECTED[@]}"; do - if [ ! -f "$file" ]; then - echo "Missing native artifact: $file" - missing=$((missing+1)) - fi - done + check "$ROOT/linux/x64/Release/InfiniFrame.Native.so" + check "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" + + check "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" + check "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" + + fi if [ "$missing" -gt 0 ]; then echo "Missing $missing native artifact(s)." From b9ab73d451c33cedc8ea48a694de3a2cc5fb4773 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 14:51:44 +0200 Subject: [PATCH 58/86] Potential fix for pull request finding 'CodeQL / Poorly documented large function' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../Windows/WebView/WebView2Attach.Win32.cpp | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp index 2ca93d097..877b618eb 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp @@ -29,15 +29,23 @@ void InfiniFrameWindow::Show(const bool isAlreadyShown) { // Initializes and attaches the WebView2 instance to this window. // +// Responsibility: +// - Perform one-shot WebView2 initialization for this native window instance. +// - Create environment/controller, apply settings, and wire all required callbacks. +// - Leave the object in a consistent state when initialization fails or is aborted. +// // High-level flow: -// 1) Bail out if the window is already closing/closed, or if initialization has already started/completed. -// 2) Resolve an optional runtime path under lock (if configured by the host). -// 3) Build browser startup arguments from feature flags and host-provided parameters. -// 4) Continue with WebView2 environment/controller creation and event wiring (below). +// 1) Bail out if the window is closing/closed, or if initialization already started/completed. +// 2) Resolve optional runtime path under lock (host-configurable global state). +// 3) Build browser startup arguments from feature flags/host parameters. +// 4) Create WebView2 environment and controller asynchronously. +// 5) Configure WebView and subscribe event handlers (navigation, messaging, permissions, etc.). +// 6) Finalize initialized flags on success; clear initializing flag on all exit paths. // -// Notes: -// - This function is intentionally stateful and order-sensitive; do not reorder guard checks. -// - The `_isWebView2Initializing` flag prevents duplicate initialization attempts. +// Notes for maintainers: +// - This function is intentionally stateful and order-sensitive; guard checks must remain first. +// - `_isWebView2Initializing` prevents duplicate concurrent initialization. +// - Async callbacks depend on stable captured values; do not convert locked snapshots to borrowed refs. void InfiniFrameWindow::AttachWebView() { // Guard: no attachment work should run after close has been requested. if (m_impl->_isClosingOrClosed.load(std::memory_order_acquire)) @@ -57,6 +65,7 @@ void InfiniFrameWindow::AttachWebView() { PCWSTR runtimePath = configuredRuntimePath.empty() ? nullptr : configuredRuntimePath.c_str(); // Compose WebView2 command-line switches from current window/browser options. + // This string is passed to environment creation and controls browser process behavior. std::wstring startupString; if (!m_impl->_userAgent.empty()) startupString += L"--user-agent=\"" + m_impl->_userAgent + L"\" "; From f98aa6617e2e85b5aa54052f36907850d98529c1 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 14:59:16 +0200 Subject: [PATCH 59/86] Refactor `download-native-binaries` action to enhance artifact handling, streamline `current-runner-only` logic, and improve verification process. --- .../download-native-binaries/action.yml | 65 +++++++++---------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 515f46429..8dc85e15d 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -63,19 +63,18 @@ runs: if [ "$current_only" = "true" ]; then case "$artifact_type" in testing) - artifact_name="native-testing-${lib}-${arch}" + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact_name=native-testing-${lib}-${arch}" >> "$GITHUB_OUTPUT" ;; release) - artifact_name="native-${lib}-${arch}" + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact_name=native-${lib}-${arch}" >> "$GITHUB_OUTPUT" ;; *) echo "Unsupported artifact-type: $artifact_type" exit 1 ;; esac - - echo "mode=name" >> "$GITHUB_OUTPUT" - echo "artifact_name=$artifact_name" >> "$GITHUB_OUTPUT" else case "$artifact_type" in testing) pattern="native-testing-*" ;; @@ -99,7 +98,7 @@ runs: - name: Download Native Build Artifacts (single) - if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'name' }} + if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'single' }} uses: actions/download-artifact@v8 with: name: ${{ steps.resolve-native-artifact-settings.outputs.artifact_name }} @@ -112,6 +111,7 @@ runs: with: pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }} path: artifacts/native + merge-multiple: true - name: Normalize Native Artifacts @@ -126,25 +126,34 @@ runs: lib="${{ steps.resolve-runner.outputs.lib }}" arch="${{ steps.resolve-runner.outputs.arch }}" - mkdir -p "$ROOT/windows/x64/Release" "$ROOT/windows/arm64/Release" - mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release" - mkdir -p "$ROOT/osx/x64/Release" "$ROOT/osx/arm64/Release" - - copy_flat() { - dest_dir="$1" - mkdir -p "$dest_dir" - cp -R artifacts/native/. "$dest_dir/" || true + mkdir -p "$ROOT/windows/x64/Release" + mkdir -p "$ROOT/windows/arm64/Release" + mkdir -p "$ROOT/linux/x64/Release" + mkdir -p "$ROOT/linux/arm64/Release" + mkdir -p "$ROOT/osx/x64/Release" + mkdir -p "$ROOT/osx/arm64/Release" + + copy() { + src="$1" + dst="$2" + if [ -d "$src" ]; then + cp -R "$src"/. "$dst"/ + fi } if [ "$current_only" = "true" ]; then - copy_flat "$ROOT/${lib}/${arch}/Release" + + copy "artifacts/native/native-${artifact_type}-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" + else - copy_flat "$ROOT/windows/x64/Release" - copy_flat "$ROOT/windows/arm64/Release" - copy_flat "$ROOT/linux/x64/Release" - copy_flat "$ROOT/linux/arm64/Release" - copy_flat "$ROOT/osx/x64/Release" - copy_flat "$ROOT/osx/arm64/Release" + + copy "artifacts/native/native-testing-windows-x64" "$ROOT/windows/x64/Release" + copy "artifacts/native/native-testing-windows-arm64" "$ROOT/windows/arm64/Release" + copy "artifacts/native/native-testing-linux-x64" "$ROOT/linux/x64/Release" + copy "artifacts/native/native-testing-linux-arm64" "$ROOT/linux/arm64/Release" + copy "artifacts/native/native-testing-osx-x64" "$ROOT/osx/x64/Release" + copy "artifacts/native/native-testing-osx-arm64" "$ROOT/osx/arm64/Release" + fi @@ -159,12 +168,10 @@ runs: lib="${{ steps.resolve-runner.outputs.lib }}" arch="${{ steps.resolve-runner.outputs.arch }}" - missing=0 - check() { if [ ! -f "$1" ]; then echo "Missing native artifact: $1" - missing=$((missing+1)) + return 1 fi } @@ -181,17 +188,12 @@ runs: osx) check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" ;; - *) - echo "Unsupported platform: $lib" - exit 1 - ;; esac else check "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" check "$ROOT/windows/x64/Release/WebView2Loader.dll" - check "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" check "$ROOT/windows/arm64/Release/WebView2Loader.dll" @@ -203,9 +205,4 @@ runs: fi - if [ "$missing" -gt 0 ]; then - echo "Missing $missing native artifact(s)." - exit 1 - fi - echo "All native artifacts downloaded and verified." \ No newline at end of file From 01fc8428ccdcf3828fb699467a215dea9d76683c Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:02:11 +0200 Subject: [PATCH 60/86] Refactor `download-native-binaries` action: replace `case` with `if-elif` for artifact type handling, update step names for clarity, and simplify artifact copy logic. --- .../download-native-binaries/action.yml | 92 +++++++++---------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 8dc85e15d..6b3e531d8 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -61,29 +61,27 @@ runs: arch="${{ steps.resolve-runner.outputs.arch }}" if [ "$current_only" = "true" ]; then - case "$artifact_type" in - testing) - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact_name=native-testing-${lib}-${arch}" >> "$GITHUB_OUTPUT" - ;; - release) - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact_name=native-${lib}-${arch}" >> "$GITHUB_OUTPUT" - ;; - *) - echo "Unsupported artifact-type: $artifact_type" - exit 1 - ;; - esac + if [ "$artifact_type" = "testing" ]; then + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact_name=native-testing-${lib}-${arch}" >> "$GITHUB_OUTPUT" + elif [ "$artifact_type" = "release" ]; then + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact_name=native-${lib}-${arch}" >> "$GITHUB_OUTPUT" + else + echo "Unsupported artifact-type: $artifact_type" + exit 1 + fi else - case "$artifact_type" in - testing) pattern="native-testing-*" ;; - release) pattern="native-*" ;; - *) echo "Unsupported artifact-type: $artifact_type"; exit 1 ;; - esac - - echo "mode=pattern" >> "$GITHUB_OUTPUT" - echo "pattern=$pattern" >> "$GITHUB_OUTPUT" + if [ "$artifact_type" = "testing" ]; then + echo "mode=all" >> "$GITHUB_OUTPUT" + echo "pattern=native-testing-*" >> "$GITHUB_OUTPUT" + elif [ "$artifact_type" = "release" ]; then + echo "mode=all" >> "$GITHUB_OUTPUT" + echo "pattern=native-*" >> "$GITHUB_OUTPUT" + else + echo "Unsupported artifact-type: $artifact_type" + exit 1 + fi fi if [ -n "$input_root" ]; then @@ -97,7 +95,7 @@ runs: echo "root=$root" >> "$GITHUB_OUTPUT" - - name: Download Native Build Artifacts (single) + - name: Download Native Build Artifacts (single runtime only) if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'single' }} uses: actions/download-artifact@v8 with: @@ -105,8 +103,8 @@ runs: path: artifacts/native - - name: Download Native Build Artifacts (all) - if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'pattern' }} + - name: Download Native Build Artifacts (all runtimes) + if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'all' }} uses: actions/download-artifact@v8 with: pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }} @@ -120,7 +118,6 @@ runs: set -euo pipefail ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" - artifact_type="${{ inputs.artifact-type }}" current_only="${{ inputs.current-runner-only }}" lib="${{ steps.resolve-runner.outputs.lib }}" @@ -133,20 +130,25 @@ runs: mkdir -p "$ROOT/osx/x64/Release" mkdir -p "$ROOT/osx/arm64/Release" - copy() { - src="$1" - dst="$2" - if [ -d "$src" ]; then - cp -R "$src"/. "$dst"/ - fi - } - if [ "$current_only" = "true" ]; then - copy "artifacts/native/native-${artifact_type}-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" + SRC="artifacts/native" + DST="$ROOT/${lib}/${arch}/Release" + + if [ -d "$SRC" ]; then + cp -R "$SRC"/. "$DST"/ + fi else + copy() { + src="$1" + dst="$2" + if [ -d "$src" ]; then + cp -R "$src"/. "$dst"/ + fi + } + copy "artifacts/native/native-testing-windows-x64" "$ROOT/windows/x64/Release" copy "artifacts/native/native-testing-windows-arm64" "$ROOT/windows/arm64/Release" copy "artifacts/native/native-testing-linux-x64" "$ROOT/linux/x64/Release" @@ -177,18 +179,14 @@ runs: if [ "$current_only" = "true" ]; then - case "$lib" in - windows) - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" - check "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" - ;; - linux) - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" - ;; - osx) - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" - ;; - esac + if [ "$lib" = "windows" ]; then + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" + check "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" + elif [ "$lib" = "linux" ]; then + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" + elif [ "$lib" = "osx" ]; then + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" + fi else From 29391016dc9eb29233d1440c4c9822ebaebb30d1 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:13:24 +0200 Subject: [PATCH 61/86] Refactor `download-native-binaries` action: simplify step logic, consolidate input handling, and improve artifact copy and verification processes. --- .../download-native-binaries/action.yml | 347 +++++++++--------- 1 file changed, 165 insertions(+), 182 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 6b3e531d8..8988e337d 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -3,17 +3,14 @@ description: Download, normalize, and verify native build artifacts for testing inputs: artifact-type: - description: Artifact naming mode required: true default: testing target-root: - description: Root path where normalized native artifacts should be written required: false default: "" current-runner-only: - description: Only download artifacts matching the current OS/arch required: false default: "false" @@ -21,186 +18,172 @@ runs: using: composite steps: - - name: Resolve Runner Platform - id: resolve-runner - shell: bash - run: | - set -euo pipefail - - os="$RUNNER_OS" - arch="$RUNNER_ARCH" - - case "$os" in - Windows) lib="windows" ;; - Linux) lib="linux" ;; - macOS) lib="osx" ;; - *) echo "Unsupported OS: $os"; exit 1 ;; - esac - - case "$arch" in - X64|x64) arch="x64" ;; - ARM64|arm64) arch="arm64" ;; - *) echo "Unsupported arch: $arch"; exit 1 ;; - esac - - echo "lib=$lib" >> "$GITHUB_OUTPUT" - echo "arch=$arch" >> "$GITHUB_OUTPUT" - - - - name: Resolve Native Artifact Settings - id: resolve-native-artifact-settings - shell: bash - run: | - set -euo pipefail - - artifact_type="${{ inputs.artifact-type }}" - input_root="${{ inputs.target-root }}" - current_only="${{ inputs.current-runner-only }}" - - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - if [ "$current_only" = "true" ]; then - if [ "$artifact_type" = "testing" ]; then - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact_name=native-testing-${lib}-${arch}" >> "$GITHUB_OUTPUT" - elif [ "$artifact_type" = "release" ]; then - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact_name=native-${lib}-${arch}" >> "$GITHUB_OUTPUT" - else - echo "Unsupported artifact-type: $artifact_type" - exit 1 - fi - else - if [ "$artifact_type" = "testing" ]; then - echo "mode=all" >> "$GITHUB_OUTPUT" - echo "pattern=native-testing-*" >> "$GITHUB_OUTPUT" - elif [ "$artifact_type" = "release" ]; then - echo "mode=all" >> "$GITHUB_OUTPUT" - echo "pattern=native-*" >> "$GITHUB_OUTPUT" - else - echo "Unsupported artifact-type: $artifact_type" - exit 1 - fi + - name: Resolve Runner Platform + id: resolve-runner + shell: bash + run: | + set -euo pipefail + + case "$RUNNER_OS" in + Windows) lib="windows" ;; + Linux) lib="linux" ;; + macOS) lib="osx" ;; + *) echo "Unsupported OS"; exit 1 ;; + esac + + case "$RUNNER_ARCH" in + X64|x64) arch="x64" ;; + ARM64|arm64) arch="arm64" ;; + *) echo "Unsupported arch"; exit 1 ;; + esac + + echo "lib=$lib" >> "$GITHUB_OUTPUT" + echo "arch=$arch" >> "$GITHUB_OUTPUT" + + + - name: Resolve Settings + id: resolve + shell: bash + run: | + set -euo pipefail + + type="${{ inputs.artifact-type }}" + current="${{ inputs.current-runner-only }}" + + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + if [ "$current" = "true" ]; then + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact=native-${type}-${lib}-${arch}" >> "$GITHUB_OUTPUT" + else + echo "mode=all" >> "$GITHUB_OUTPUT" + echo "pattern=native-${type}-*" >> "$GITHUB_OUTPUT" + fi + + if [ -n "${{ inputs.target-root }}" ]; then + root="${{ inputs.target-root }}" + elif [ "$type" = "testing" ]; then + root="src/InfiniFrame.NativeBridge/artifacts/native" + else + root="artifacts/native" + fi + + echo "root=$root" >> "$GITHUB_OUTPUT" + + + - name: Download (single) + if: ${{ steps.resolve.outputs.mode == 'single' }} + uses: actions/download-artifact@v8 + with: + name: ${{ steps.resolve.outputs.artifact }} + path: artifacts/native + + + - name: Download (all) + if: ${{ steps.resolve.outputs.mode == 'all' }} + uses: actions/download-artifact@v8 + with: + pattern: ${{ steps.resolve.outputs.pattern }} + merge-multiple: true + path: artifacts/native + + + - name: Normalize + shell: bash + run: | + set -euo pipefail + + ROOT="${{ steps.resolve.outputs.root }}" + MODE="${{ steps.resolve.outputs.mode }}" + LIB="${{ steps.resolve-runner.outputs.lib }}" + ARCH="${{ steps.resolve-runner.outputs.arch }}" + + mkdir -p "$ROOT/windows/x64/Release" + mkdir -p "$ROOT/windows/arm64/Release" + mkdir -p "$ROOT/linux/x64/Release" + mkdir -p "$ROOT/linux/arm64/Release" + mkdir -p "$ROOT/osx/x64/Release" + mkdir -p "$ROOT/osx/arm64/Release" + + copy() { + src="$1" + dst="$2" + + if [ ! -d "$src" ]; then + echo "⚠️ Missing artifact folder: $src" + return fi - - if [ -n "$input_root" ]; then - root="$input_root" - elif [ "$artifact_type" = "testing" ]; then - root="src/InfiniFrame.NativeBridge/artifacts/native" + + echo "Copying $src -> $dst" + cp -R "$src"/. "$dst"/ + } + + if [ "$MODE" = "single" ]; then + + SRC="artifacts/native/native-testing-${LIB}-${ARCH}" + if [ -d "$SRC" ]; then + copy "$SRC" "$ROOT/${LIB}/${ARCH}/Release" else - root="artifacts/native" + echo "❌ Expected artifact missing: $SRC" + exit 1 fi - - echo "root=$root" >> "$GITHUB_OUTPUT" - - - - name: Download Native Build Artifacts (single runtime only) - if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'single' }} - uses: actions/download-artifact@v8 - with: - name: ${{ steps.resolve-native-artifact-settings.outputs.artifact_name }} - path: artifacts/native - - - - name: Download Native Build Artifacts (all runtimes) - if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'all' }} - uses: actions/download-artifact@v8 - with: - pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }} - path: artifacts/native - merge-multiple: true - - - - name: Normalize Native Artifacts - shell: bash - run: | - set -euo pipefail - - ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" - current_only="${{ inputs.current-runner-only }}" - - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - mkdir -p "$ROOT/windows/x64/Release" - mkdir -p "$ROOT/windows/arm64/Release" - mkdir -p "$ROOT/linux/x64/Release" - mkdir -p "$ROOT/linux/arm64/Release" - mkdir -p "$ROOT/osx/x64/Release" - mkdir -p "$ROOT/osx/arm64/Release" - - if [ "$current_only" = "true" ]; then - - SRC="artifacts/native" - DST="$ROOT/${lib}/${arch}/Release" - - if [ -d "$SRC" ]; then - cp -R "$SRC"/. "$DST"/ - fi - - else - - copy() { - src="$1" - dst="$2" - if [ -d "$src" ]; then - cp -R "$src"/. "$dst"/ - fi - } - - copy "artifacts/native/native-testing-windows-x64" "$ROOT/windows/x64/Release" - copy "artifacts/native/native-testing-windows-arm64" "$ROOT/windows/arm64/Release" - copy "artifacts/native/native-testing-linux-x64" "$ROOT/linux/x64/Release" - copy "artifacts/native/native-testing-linux-arm64" "$ROOT/linux/arm64/Release" - copy "artifacts/native/native-testing-osx-x64" "$ROOT/osx/x64/Release" - copy "artifacts/native/native-testing-osx-arm64" "$ROOT/osx/arm64/Release" - + + else + + for f in \ + windows-x64 \ + windows-arm64 \ + linux-x64 \ + linux-arm64 \ + osx-x64 \ + osx-arm64 + do + copy "artifacts/native/native-testing-$f" "$ROOT/${f//-//}/Release" + done + + fi + + + - name: Verify + shell: bash + run: | + set -euo pipefail + + ROOT="${{ steps.resolve.outputs.root }}" + MODE="${{ steps.resolve.outputs.mode }}" + LIB="${{ steps.resolve-runner.outputs.lib }}" + ARCH="${{ steps.resolve-runner.outputs.arch }}" + + check() { + if [ ! -f "$1" ]; then + echo "Missing: $1" + exit 1 fi - - - - name: Verify Native Artifacts - shell: bash - run: | - set -euo pipefail - - ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" - current_only="${{ inputs.current-runner-only }}" - - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - check() { - if [ ! -f "$1" ]; then - echo "Missing native artifact: $1" - return 1 - fi - } - - if [ "$current_only" = "true" ]; then - - if [ "$lib" = "windows" ]; then - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" - check "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" - elif [ "$lib" = "linux" ]; then - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" - elif [ "$lib" = "osx" ]; then - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" - fi - - else - - check "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" - check "$ROOT/windows/x64/Release/WebView2Loader.dll" - check "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" - check "$ROOT/windows/arm64/Release/WebView2Loader.dll" - - check "$ROOT/linux/x64/Release/InfiniFrame.Native.so" - check "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" - - check "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" - check "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" - - fi - - echo "All native artifacts downloaded and verified." \ No newline at end of file + } + + if [ "$MODE" = "single" ]; then + + case "$LIB" in + windows) + check "$ROOT/$LIB/$ARCH/Release/InfiniFrame.Native.dll" + check "$ROOT/$LIB/$ARCH/Release/WebView2Loader.dll" + ;; + linux) + check "$ROOT/$LIB/$ARCH/Release/InfiniFrame.Native.so" + ;; + osx) + check "$ROOT/$LIB/$ARCH/Release/InfiniFrame.Native.dylib" + ;; + esac + + else + + check "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" + check "$ROOT/windows/arm64/Release/WebView2Loader.dll" + check "$ROOT/linux/x64/Release/InfiniFrame.Native.so" + check "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" + + fi + + echo "OK" \ No newline at end of file From abfc68063758e30b192d995bd33aaf66cca2123f Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:27:05 +0200 Subject: [PATCH 62/86] Revert "Refactor `download-native-binaries` action: simplify step logic, consolidate input handling, and improve artifact copy and verification processes." This reverts commit 29391016dc9eb29233d1440c4c9822ebaebb30d1. --- .../download-native-binaries/action.yml | 347 +++++++++--------- 1 file changed, 182 insertions(+), 165 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 8988e337d..6b3e531d8 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -3,14 +3,17 @@ description: Download, normalize, and verify native build artifacts for testing inputs: artifact-type: + description: Artifact naming mode required: true default: testing target-root: + description: Root path where normalized native artifacts should be written required: false default: "" current-runner-only: + description: Only download artifacts matching the current OS/arch required: false default: "false" @@ -18,172 +21,186 @@ runs: using: composite steps: - - name: Resolve Runner Platform - id: resolve-runner - shell: bash - run: | - set -euo pipefail - - case "$RUNNER_OS" in - Windows) lib="windows" ;; - Linux) lib="linux" ;; - macOS) lib="osx" ;; - *) echo "Unsupported OS"; exit 1 ;; - esac - - case "$RUNNER_ARCH" in - X64|x64) arch="x64" ;; - ARM64|arm64) arch="arm64" ;; - *) echo "Unsupported arch"; exit 1 ;; - esac - - echo "lib=$lib" >> "$GITHUB_OUTPUT" - echo "arch=$arch" >> "$GITHUB_OUTPUT" - - - - name: Resolve Settings - id: resolve - shell: bash - run: | - set -euo pipefail - - type="${{ inputs.artifact-type }}" - current="${{ inputs.current-runner-only }}" - - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - if [ "$current" = "true" ]; then - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact=native-${type}-${lib}-${arch}" >> "$GITHUB_OUTPUT" - else - echo "mode=all" >> "$GITHUB_OUTPUT" - echo "pattern=native-${type}-*" >> "$GITHUB_OUTPUT" - fi - - if [ -n "${{ inputs.target-root }}" ]; then - root="${{ inputs.target-root }}" - elif [ "$type" = "testing" ]; then - root="src/InfiniFrame.NativeBridge/artifacts/native" - else - root="artifacts/native" - fi - - echo "root=$root" >> "$GITHUB_OUTPUT" - - - - name: Download (single) - if: ${{ steps.resolve.outputs.mode == 'single' }} - uses: actions/download-artifact@v8 - with: - name: ${{ steps.resolve.outputs.artifact }} - path: artifacts/native - - - - name: Download (all) - if: ${{ steps.resolve.outputs.mode == 'all' }} - uses: actions/download-artifact@v8 - with: - pattern: ${{ steps.resolve.outputs.pattern }} - merge-multiple: true - path: artifacts/native - - - - name: Normalize - shell: bash - run: | - set -euo pipefail - - ROOT="${{ steps.resolve.outputs.root }}" - MODE="${{ steps.resolve.outputs.mode }}" - LIB="${{ steps.resolve-runner.outputs.lib }}" - ARCH="${{ steps.resolve-runner.outputs.arch }}" - - mkdir -p "$ROOT/windows/x64/Release" - mkdir -p "$ROOT/windows/arm64/Release" - mkdir -p "$ROOT/linux/x64/Release" - mkdir -p "$ROOT/linux/arm64/Release" - mkdir -p "$ROOT/osx/x64/Release" - mkdir -p "$ROOT/osx/arm64/Release" - - copy() { - src="$1" - dst="$2" - - if [ ! -d "$src" ]; then - echo "⚠️ Missing artifact folder: $src" - return + - name: Resolve Runner Platform + id: resolve-runner + shell: bash + run: | + set -euo pipefail + + os="$RUNNER_OS" + arch="$RUNNER_ARCH" + + case "$os" in + Windows) lib="windows" ;; + Linux) lib="linux" ;; + macOS) lib="osx" ;; + *) echo "Unsupported OS: $os"; exit 1 ;; + esac + + case "$arch" in + X64|x64) arch="x64" ;; + ARM64|arm64) arch="arm64" ;; + *) echo "Unsupported arch: $arch"; exit 1 ;; + esac + + echo "lib=$lib" >> "$GITHUB_OUTPUT" + echo "arch=$arch" >> "$GITHUB_OUTPUT" + + + - name: Resolve Native Artifact Settings + id: resolve-native-artifact-settings + shell: bash + run: | + set -euo pipefail + + artifact_type="${{ inputs.artifact-type }}" + input_root="${{ inputs.target-root }}" + current_only="${{ inputs.current-runner-only }}" + + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + if [ "$current_only" = "true" ]; then + if [ "$artifact_type" = "testing" ]; then + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact_name=native-testing-${lib}-${arch}" >> "$GITHUB_OUTPUT" + elif [ "$artifact_type" = "release" ]; then + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact_name=native-${lib}-${arch}" >> "$GITHUB_OUTPUT" + else + echo "Unsupported artifact-type: $artifact_type" + exit 1 + fi + else + if [ "$artifact_type" = "testing" ]; then + echo "mode=all" >> "$GITHUB_OUTPUT" + echo "pattern=native-testing-*" >> "$GITHUB_OUTPUT" + elif [ "$artifact_type" = "release" ]; then + echo "mode=all" >> "$GITHUB_OUTPUT" + echo "pattern=native-*" >> "$GITHUB_OUTPUT" + else + echo "Unsupported artifact-type: $artifact_type" + exit 1 + fi fi - - echo "Copying $src -> $dst" - cp -R "$src"/. "$dst"/ - } - - if [ "$MODE" = "single" ]; then - - SRC="artifacts/native/native-testing-${LIB}-${ARCH}" - if [ -d "$SRC" ]; then - copy "$SRC" "$ROOT/${LIB}/${ARCH}/Release" + + if [ -n "$input_root" ]; then + root="$input_root" + elif [ "$artifact_type" = "testing" ]; then + root="src/InfiniFrame.NativeBridge/artifacts/native" else - echo "❌ Expected artifact missing: $SRC" - exit 1 + root="artifacts/native" fi - - else - - for f in \ - windows-x64 \ - windows-arm64 \ - linux-x64 \ - linux-arm64 \ - osx-x64 \ - osx-arm64 - do - copy "artifacts/native/native-testing-$f" "$ROOT/${f//-//}/Release" - done - - fi - - - - name: Verify - shell: bash - run: | - set -euo pipefail - - ROOT="${{ steps.resolve.outputs.root }}" - MODE="${{ steps.resolve.outputs.mode }}" - LIB="${{ steps.resolve-runner.outputs.lib }}" - ARCH="${{ steps.resolve-runner.outputs.arch }}" - - check() { - if [ ! -f "$1" ]; then - echo "Missing: $1" - exit 1 + + echo "root=$root" >> "$GITHUB_OUTPUT" + + + - name: Download Native Build Artifacts (single runtime only) + if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'single' }} + uses: actions/download-artifact@v8 + with: + name: ${{ steps.resolve-native-artifact-settings.outputs.artifact_name }} + path: artifacts/native + + + - name: Download Native Build Artifacts (all runtimes) + if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'all' }} + uses: actions/download-artifact@v8 + with: + pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }} + path: artifacts/native + merge-multiple: true + + + - name: Normalize Native Artifacts + shell: bash + run: | + set -euo pipefail + + ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" + current_only="${{ inputs.current-runner-only }}" + + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + mkdir -p "$ROOT/windows/x64/Release" + mkdir -p "$ROOT/windows/arm64/Release" + mkdir -p "$ROOT/linux/x64/Release" + mkdir -p "$ROOT/linux/arm64/Release" + mkdir -p "$ROOT/osx/x64/Release" + mkdir -p "$ROOT/osx/arm64/Release" + + if [ "$current_only" = "true" ]; then + + SRC="artifacts/native" + DST="$ROOT/${lib}/${arch}/Release" + + if [ -d "$SRC" ]; then + cp -R "$SRC"/. "$DST"/ + fi + + else + + copy() { + src="$1" + dst="$2" + if [ -d "$src" ]; then + cp -R "$src"/. "$dst"/ + fi + } + + copy "artifacts/native/native-testing-windows-x64" "$ROOT/windows/x64/Release" + copy "artifacts/native/native-testing-windows-arm64" "$ROOT/windows/arm64/Release" + copy "artifacts/native/native-testing-linux-x64" "$ROOT/linux/x64/Release" + copy "artifacts/native/native-testing-linux-arm64" "$ROOT/linux/arm64/Release" + copy "artifacts/native/native-testing-osx-x64" "$ROOT/osx/x64/Release" + copy "artifacts/native/native-testing-osx-arm64" "$ROOT/osx/arm64/Release" + fi - } - - if [ "$MODE" = "single" ]; then - - case "$LIB" in - windows) - check "$ROOT/$LIB/$ARCH/Release/InfiniFrame.Native.dll" - check "$ROOT/$LIB/$ARCH/Release/WebView2Loader.dll" - ;; - linux) - check "$ROOT/$LIB/$ARCH/Release/InfiniFrame.Native.so" - ;; - osx) - check "$ROOT/$LIB/$ARCH/Release/InfiniFrame.Native.dylib" - ;; - esac - - else - - check "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" - check "$ROOT/windows/arm64/Release/WebView2Loader.dll" - check "$ROOT/linux/x64/Release/InfiniFrame.Native.so" - check "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" - - fi - - echo "OK" \ No newline at end of file + + + - name: Verify Native Artifacts + shell: bash + run: | + set -euo pipefail + + ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" + current_only="${{ inputs.current-runner-only }}" + + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + check() { + if [ ! -f "$1" ]; then + echo "Missing native artifact: $1" + return 1 + fi + } + + if [ "$current_only" = "true" ]; then + + if [ "$lib" = "windows" ]; then + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" + check "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" + elif [ "$lib" = "linux" ]; then + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" + elif [ "$lib" = "osx" ]; then + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" + fi + + else + + check "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" + check "$ROOT/windows/x64/Release/WebView2Loader.dll" + check "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" + check "$ROOT/windows/arm64/Release/WebView2Loader.dll" + + check "$ROOT/linux/x64/Release/InfiniFrame.Native.so" + check "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" + + check "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" + check "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" + + fi + + echo "All native artifacts downloaded and verified." \ No newline at end of file From 3a4c709dbbb644df412794c78427cc16dd6260c6 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:27:08 +0200 Subject: [PATCH 63/86] Revert "Refactor `download-native-binaries` action: replace `case` with `if-elif` for artifact type handling, update step names for clarity, and simplify artifact copy logic." This reverts commit 01fc8428ccdcf3828fb699467a215dea9d76683c. --- .../download-native-binaries/action.yml | 92 ++++++++++--------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 6b3e531d8..8dc85e15d 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -61,27 +61,29 @@ runs: arch="${{ steps.resolve-runner.outputs.arch }}" if [ "$current_only" = "true" ]; then - if [ "$artifact_type" = "testing" ]; then - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact_name=native-testing-${lib}-${arch}" >> "$GITHUB_OUTPUT" - elif [ "$artifact_type" = "release" ]; then - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact_name=native-${lib}-${arch}" >> "$GITHUB_OUTPUT" - else - echo "Unsupported artifact-type: $artifact_type" - exit 1 - fi + case "$artifact_type" in + testing) + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact_name=native-testing-${lib}-${arch}" >> "$GITHUB_OUTPUT" + ;; + release) + echo "mode=single" >> "$GITHUB_OUTPUT" + echo "artifact_name=native-${lib}-${arch}" >> "$GITHUB_OUTPUT" + ;; + *) + echo "Unsupported artifact-type: $artifact_type" + exit 1 + ;; + esac else - if [ "$artifact_type" = "testing" ]; then - echo "mode=all" >> "$GITHUB_OUTPUT" - echo "pattern=native-testing-*" >> "$GITHUB_OUTPUT" - elif [ "$artifact_type" = "release" ]; then - echo "mode=all" >> "$GITHUB_OUTPUT" - echo "pattern=native-*" >> "$GITHUB_OUTPUT" - else - echo "Unsupported artifact-type: $artifact_type" - exit 1 - fi + case "$artifact_type" in + testing) pattern="native-testing-*" ;; + release) pattern="native-*" ;; + *) echo "Unsupported artifact-type: $artifact_type"; exit 1 ;; + esac + + echo "mode=pattern" >> "$GITHUB_OUTPUT" + echo "pattern=$pattern" >> "$GITHUB_OUTPUT" fi if [ -n "$input_root" ]; then @@ -95,7 +97,7 @@ runs: echo "root=$root" >> "$GITHUB_OUTPUT" - - name: Download Native Build Artifacts (single runtime only) + - name: Download Native Build Artifacts (single) if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'single' }} uses: actions/download-artifact@v8 with: @@ -103,8 +105,8 @@ runs: path: artifacts/native - - name: Download Native Build Artifacts (all runtimes) - if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'all' }} + - name: Download Native Build Artifacts (all) + if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'pattern' }} uses: actions/download-artifact@v8 with: pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }} @@ -118,6 +120,7 @@ runs: set -euo pipefail ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" + artifact_type="${{ inputs.artifact-type }}" current_only="${{ inputs.current-runner-only }}" lib="${{ steps.resolve-runner.outputs.lib }}" @@ -130,24 +133,19 @@ runs: mkdir -p "$ROOT/osx/x64/Release" mkdir -p "$ROOT/osx/arm64/Release" - if [ "$current_only" = "true" ]; then - - SRC="artifacts/native" - DST="$ROOT/${lib}/${arch}/Release" - - if [ -d "$SRC" ]; then - cp -R "$SRC"/. "$DST"/ - fi - - else - - copy() { + copy() { src="$1" dst="$2" if [ -d "$src" ]; then - cp -R "$src"/. "$dst"/ + cp -R "$src"/. "$dst"/ fi - } + } + + if [ "$current_only" = "true" ]; then + + copy "artifacts/native/native-${artifact_type}-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" + + else copy "artifacts/native/native-testing-windows-x64" "$ROOT/windows/x64/Release" copy "artifacts/native/native-testing-windows-arm64" "$ROOT/windows/arm64/Release" @@ -179,14 +177,18 @@ runs: if [ "$current_only" = "true" ]; then - if [ "$lib" = "windows" ]; then - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" - check "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" - elif [ "$lib" = "linux" ]; then - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" - elif [ "$lib" = "osx" ]; then - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" - fi + case "$lib" in + windows) + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" + check "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" + ;; + linux) + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" + ;; + osx) + check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" + ;; + esac else From 8725980cdd5750b54a32f4882b770a57632e3c81 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:27:12 +0200 Subject: [PATCH 64/86] Revert "Refactor `download-native-binaries` action to enhance artifact handling, streamline `current-runner-only` logic, and improve verification process." This reverts commit f98aa6617e2e85b5aa54052f36907850d98529c1. --- .../download-native-binaries/action.yml | 65 ++++++++++--------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 8dc85e15d..515f46429 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -63,18 +63,19 @@ runs: if [ "$current_only" = "true" ]; then case "$artifact_type" in testing) - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact_name=native-testing-${lib}-${arch}" >> "$GITHUB_OUTPUT" + artifact_name="native-testing-${lib}-${arch}" ;; release) - echo "mode=single" >> "$GITHUB_OUTPUT" - echo "artifact_name=native-${lib}-${arch}" >> "$GITHUB_OUTPUT" + artifact_name="native-${lib}-${arch}" ;; *) echo "Unsupported artifact-type: $artifact_type" exit 1 ;; esac + + echo "mode=name" >> "$GITHUB_OUTPUT" + echo "artifact_name=$artifact_name" >> "$GITHUB_OUTPUT" else case "$artifact_type" in testing) pattern="native-testing-*" ;; @@ -98,7 +99,7 @@ runs: - name: Download Native Build Artifacts (single) - if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'single' }} + if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'name' }} uses: actions/download-artifact@v8 with: name: ${{ steps.resolve-native-artifact-settings.outputs.artifact_name }} @@ -111,7 +112,6 @@ runs: with: pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }} path: artifacts/native - merge-multiple: true - name: Normalize Native Artifacts @@ -126,34 +126,25 @@ runs: lib="${{ steps.resolve-runner.outputs.lib }}" arch="${{ steps.resolve-runner.outputs.arch }}" - mkdir -p "$ROOT/windows/x64/Release" - mkdir -p "$ROOT/windows/arm64/Release" - mkdir -p "$ROOT/linux/x64/Release" - mkdir -p "$ROOT/linux/arm64/Release" - mkdir -p "$ROOT/osx/x64/Release" - mkdir -p "$ROOT/osx/arm64/Release" - - copy() { - src="$1" - dst="$2" - if [ -d "$src" ]; then - cp -R "$src"/. "$dst"/ - fi + mkdir -p "$ROOT/windows/x64/Release" "$ROOT/windows/arm64/Release" + mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release" + mkdir -p "$ROOT/osx/x64/Release" "$ROOT/osx/arm64/Release" + + copy_flat() { + dest_dir="$1" + mkdir -p "$dest_dir" + cp -R artifacts/native/. "$dest_dir/" || true } if [ "$current_only" = "true" ]; then - - copy "artifacts/native/native-${artifact_type}-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" - + copy_flat "$ROOT/${lib}/${arch}/Release" else - - copy "artifacts/native/native-testing-windows-x64" "$ROOT/windows/x64/Release" - copy "artifacts/native/native-testing-windows-arm64" "$ROOT/windows/arm64/Release" - copy "artifacts/native/native-testing-linux-x64" "$ROOT/linux/x64/Release" - copy "artifacts/native/native-testing-linux-arm64" "$ROOT/linux/arm64/Release" - copy "artifacts/native/native-testing-osx-x64" "$ROOT/osx/x64/Release" - copy "artifacts/native/native-testing-osx-arm64" "$ROOT/osx/arm64/Release" - + copy_flat "$ROOT/windows/x64/Release" + copy_flat "$ROOT/windows/arm64/Release" + copy_flat "$ROOT/linux/x64/Release" + copy_flat "$ROOT/linux/arm64/Release" + copy_flat "$ROOT/osx/x64/Release" + copy_flat "$ROOT/osx/arm64/Release" fi @@ -168,10 +159,12 @@ runs: lib="${{ steps.resolve-runner.outputs.lib }}" arch="${{ steps.resolve-runner.outputs.arch }}" + missing=0 + check() { if [ ! -f "$1" ]; then echo "Missing native artifact: $1" - return 1 + missing=$((missing+1)) fi } @@ -188,12 +181,17 @@ runs: osx) check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" ;; + *) + echo "Unsupported platform: $lib" + exit 1 + ;; esac else check "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" check "$ROOT/windows/x64/Release/WebView2Loader.dll" + check "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" check "$ROOT/windows/arm64/Release/WebView2Loader.dll" @@ -205,4 +203,9 @@ runs: fi + if [ "$missing" -gt 0 ]; then + echo "Missing $missing native artifact(s)." + exit 1 + fi + echo "All native artifacts downloaded and verified." \ No newline at end of file From afbbdaf19e8be0d29e3e4c36f26b99e6c995af09 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:27:17 +0200 Subject: [PATCH 65/86] Revert "Refactor `download-native-binaries` action to streamline artifact copy/verification logic and improve `current-runner-only` handling." This reverts commit f210f8e7962b1ea0a2d359174f70e9331c19c01f. --- .../download-native-binaries/action.yml | 99 ++++++++++--------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 515f46429..8ea888616 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -123,9 +123,6 @@ runs: artifact_type="${{ inputs.artifact-type }}" current_only="${{ inputs.current-runner-only }}" - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - mkdir -p "$ROOT/windows/x64/Release" "$ROOT/windows/arm64/Release" mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release" mkdir -p "$ROOT/osx/x64/Release" "$ROOT/osx/arm64/Release" @@ -136,15 +133,35 @@ runs: cp -R artifacts/native/. "$dest_dir/" || true } - if [ "$current_only" = "true" ]; then - copy_flat "$ROOT/${lib}/${arch}/Release" + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + if [ "$artifact_type" = "testing" ]; then + + if [ "$current_only" = "true" ]; then + copy_flat "$ROOT/${lib}/${arch}/Release" + else + copy_flat "$ROOT/windows/x64/Release" + copy_flat "$ROOT/windows/arm64/Release" + copy_flat "$ROOT/linux/x64/Release" + copy_flat "$ROOT/linux/arm64/Release" + copy_flat "$ROOT/osx/x64/Release" + copy_flat "$ROOT/osx/arm64/Release" + fi + else - copy_flat "$ROOT/windows/x64/Release" - copy_flat "$ROOT/windows/arm64/Release" - copy_flat "$ROOT/linux/x64/Release" - copy_flat "$ROOT/linux/arm64/Release" - copy_flat "$ROOT/osx/x64/Release" - copy_flat "$ROOT/osx/arm64/Release" + + if [ "$current_only" = "true" ]; then + copy_flat "$ROOT/${lib}/${arch}/Release" + else + copy_flat "$ROOT/windows/x64/Release" + copy_flat "$ROOT/windows/arm64/Release" + copy_flat "$ROOT/linux/x64/Release" + copy_flat "$ROOT/linux/arm64/Release" + copy_flat "$ROOT/osx/x64/Release" + copy_flat "$ROOT/osx/arm64/Release" + fi + fi @@ -159,50 +176,38 @@ runs: lib="${{ steps.resolve-runner.outputs.lib }}" arch="${{ steps.resolve-runner.outputs.arch }}" - missing=0 - - check() { - if [ ! -f "$1" ]; then - echo "Missing native artifact: $1" - missing=$((missing+1)) - fi - } - if [ "$current_only" = "true" ]; then - case "$lib" in - windows) - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" - check "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" - ;; - linux) - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" - ;; - osx) - check "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" - ;; - *) - echo "Unsupported platform: $lib" - exit 1 - ;; - esac + EXPECTED=( + "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" + "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" + "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" + "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" + ) else - check "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" - check "$ROOT/windows/x64/Release/WebView2Loader.dll" - - check "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" - check "$ROOT/windows/arm64/Release/WebView2Loader.dll" - - check "$ROOT/linux/x64/Release/InfiniFrame.Native.so" - check "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" - - check "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" - check "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" + EXPECTED=( + "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" + "$ROOT/windows/x64/Release/WebView2Loader.dll" + "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" + "$ROOT/windows/arm64/Release/WebView2Loader.dll" + "$ROOT/linux/x64/Release/InfiniFrame.Native.so" + "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" + "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" + "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" + ) fi + missing=0 + for file in "${EXPECTED[@]}"; do + if [ ! -f "$file" ]; then + echo "Missing native artifact: $file" + missing=$((missing+1)) + fi + done + if [ "$missing" -gt 0 ]; then echo "Missing $missing native artifact(s)." exit 1 From ae7c5d2dccaf202f01ce8117efb882b22ce662f3 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:27:28 +0200 Subject: [PATCH 66/86] Revert "Simplify artifact copy logic in `download-native-binaries` action by replacing `copy_artifact` with `copy_flat`." This reverts commit 611dc816b19d7d28f68e71bd07a58e12ad0735ed. --- .../download-native-binaries/action.yml | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 8ea888616..6f4b8d860 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -127,39 +127,46 @@ runs: mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release" mkdir -p "$ROOT/osx/x64/Release" "$ROOT/osx/arm64/Release" - copy_flat() { - dest_dir="$1" - mkdir -p "$dest_dir" - cp -R artifacts/native/. "$dest_dir/" || true + copy_artifact() { + src_name="$1" + dest_dir="$2" + src="artifacts/native/$src_name" + + if [ -d "$src" ]; then + cp -R "$src"/. "$dest_dir"/ + fi } - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - if [ "$artifact_type" = "testing" ]; then if [ "$current_only" = "true" ]; then - copy_flat "$ROOT/${lib}/${arch}/Release" + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + copy_artifact "native-testing-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" else - copy_flat "$ROOT/windows/x64/Release" - copy_flat "$ROOT/windows/arm64/Release" - copy_flat "$ROOT/linux/x64/Release" - copy_flat "$ROOT/linux/arm64/Release" - copy_flat "$ROOT/osx/x64/Release" - copy_flat "$ROOT/osx/arm64/Release" + copy_artifact "native-testing-windows-x64" "$ROOT/windows/x64/Release" + copy_artifact "native-testing-windows-arm64" "$ROOT/windows/arm64/Release" + copy_artifact "native-testing-linux-x64" "$ROOT/linux/x64/Release" + copy_artifact "native-testing-linux-arm64" "$ROOT/linux/arm64/Release" + copy_artifact "native-testing-osx-x64" "$ROOT/osx/x64/Release" + copy_artifact "native-testing-osx-arm64" "$ROOT/osx/arm64/Release" fi else if [ "$current_only" = "true" ]; then - copy_flat "$ROOT/${lib}/${arch}/Release" + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + + copy_artifact "native-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" else - copy_flat "$ROOT/windows/x64/Release" - copy_flat "$ROOT/windows/arm64/Release" - copy_flat "$ROOT/linux/x64/Release" - copy_flat "$ROOT/linux/arm64/Release" - copy_flat "$ROOT/osx/x64/Release" - copy_flat "$ROOT/osx/arm64/Release" + copy_artifact "native-windows-x64" "$ROOT/windows/x64/Release" + copy_artifact "native-windows-arm64" "$ROOT/windows/arm64/Release" + copy_artifact "native-linux-x64" "$ROOT/linux/x64/Release" + copy_artifact "native-linux-arm64" "$ROOT/linux/arm64/Release" + copy_artifact "native-osx-x64" "$ROOT/osx/x64/Release" + copy_artifact "native-osx-arm64" "$ROOT/osx/arm64/Release" fi fi @@ -173,11 +180,11 @@ runs: ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" current_only="${{ inputs.current-runner-only }}" - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - if [ "$current_only" = "true" ]; then + lib="${{ steps.resolve-runner.outputs.lib }}" + arch="${{ steps.resolve-runner.outputs.arch }}" + EXPECTED=( "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" From 79355fa08b43dcd376a1b213207c22b05e443366 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:27:33 +0200 Subject: [PATCH 67/86] Revert "Refactor `download-native-binaries` action for cleaner syntax and improved `current-runner-only` support" This reverts commit 25f1fb783e61e2d3a7cf24f24361e0b1f146a5d6. --- .../download-native-binaries/action.yml | 104 ++++++++---------- 1 file changed, 45 insertions(+), 59 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 6f4b8d860..67301cddc 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -31,16 +31,32 @@ runs: arch="$RUNNER_ARCH" case "$os" in - Windows) lib="windows" ;; - Linux) lib="linux" ;; - macOS) lib="osx" ;; - *) echo "Unsupported OS: $os"; exit 1 ;; + Windows) + lib="windows" + ;; + Linux) + lib="linux" + ;; + macOS) + lib="osx" + ;; + *) + echo "Unsupported OS: $os" + exit 1 + ;; esac case "$arch" in - X64|x64) arch="x64" ;; - ARM64|arm64) arch="arm64" ;; - *) echo "Unsupported arch: $arch"; exit 1 ;; + X64|x64) + arch="x64" + ;; + ARM64|arm64) + arch="arm64" + ;; + *) + echo "Unsupported arch: $arch" + exit 1 + ;; esac echo "lib=$lib" >> "$GITHUB_OUTPUT" @@ -78,9 +94,16 @@ runs: echo "artifact_name=$artifact_name" >> "$GITHUB_OUTPUT" else case "$artifact_type" in - testing) pattern="native-testing-*" ;; - release) pattern="native-*" ;; - *) echo "Unsupported artifact-type: $artifact_type"; exit 1 ;; + testing) + pattern="native-testing-*" + ;; + release) + pattern="native-*" + ;; + *) + echo "Unsupported artifact-type: $artifact_type" + exit 1 + ;; esac echo "mode=pattern" >> "$GITHUB_OUTPUT" @@ -98,7 +121,7 @@ runs: echo "root=$root" >> "$GITHUB_OUTPUT" - - name: Download Native Build Artifacts (single) + - name: Download Native Build Artifacts (current runner only) if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'name' }} uses: actions/download-artifact@v8 with: @@ -106,7 +129,7 @@ runs: path: artifacts/native - - name: Download Native Build Artifacts (all) + - name: Download Native Build Artifacts (all platforms) if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'pattern' }} uses: actions/download-artifact@v8 with: @@ -121,7 +144,6 @@ runs: ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" artifact_type="${{ inputs.artifact-type }}" - current_only="${{ inputs.current-runner-only }}" mkdir -p "$ROOT/windows/x64/Release" "$ROOT/windows/arm64/Release" mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release" @@ -131,44 +153,25 @@ runs: src_name="$1" dest_dir="$2" src="artifacts/native/$src_name" - if [ -d "$src" ]; then cp -R "$src"/. "$dest_dir"/ fi } if [ "$artifact_type" = "testing" ]; then - - if [ "$current_only" = "true" ]; then - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - copy_artifact "native-testing-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" - else copy_artifact "native-testing-windows-x64" "$ROOT/windows/x64/Release" copy_artifact "native-testing-windows-arm64" "$ROOT/windows/arm64/Release" copy_artifact "native-testing-linux-x64" "$ROOT/linux/x64/Release" copy_artifact "native-testing-linux-arm64" "$ROOT/linux/arm64/Release" copy_artifact "native-testing-osx-x64" "$ROOT/osx/x64/Release" copy_artifact "native-testing-osx-arm64" "$ROOT/osx/arm64/Release" - fi - else - - if [ "$current_only" = "true" ]; then - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - copy_artifact "native-${lib}-${arch}" "$ROOT/${lib}/${arch}/Release" - else copy_artifact "native-windows-x64" "$ROOT/windows/x64/Release" copy_artifact "native-windows-arm64" "$ROOT/windows/arm64/Release" copy_artifact "native-linux-x64" "$ROOT/linux/x64/Release" copy_artifact "native-linux-arm64" "$ROOT/linux/arm64/Release" copy_artifact "native-osx-x64" "$ROOT/osx/x64/Release" copy_artifact "native-osx-arm64" "$ROOT/osx/arm64/Release" - fi - fi @@ -178,34 +181,17 @@ runs: set -euo pipefail ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" - current_only="${{ inputs.current-runner-only }}" - - if [ "$current_only" = "true" ]; then - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - EXPECTED=( - "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dll" - "$ROOT/${lib}/${arch}/Release/WebView2Loader.dll" - "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.so" - "$ROOT/${lib}/${arch}/Release/InfiniFrame.Native.dylib" - ) - - else - - EXPECTED=( - "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" - "$ROOT/windows/x64/Release/WebView2Loader.dll" - "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" - "$ROOT/windows/arm64/Release/WebView2Loader.dll" - "$ROOT/linux/x64/Release/InfiniFrame.Native.so" - "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" - "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" - "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" - ) - - fi + EXPECTED=( + "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" + "$ROOT/windows/x64/Release/WebView2Loader.dll" + "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll" + "$ROOT/windows/arm64/Release/WebView2Loader.dll" + "$ROOT/linux/x64/Release/InfiniFrame.Native.so" + "$ROOT/linux/arm64/Release/InfiniFrame.Native.so" + "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib" + "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib" + ) missing=0 for file in "${EXPECTED[@]}"; do From 062c8d3302666466d032d3df2b06996cc8baab1f Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:27:43 +0200 Subject: [PATCH 68/86] Revert "Add `current-runner-only` option to `download-native-binaries` action and update workflows" This reverts commit a07e97e64a1a207ef88665534f6e04cacd343ada. --- .../download-native-binaries/action.yml | 112 ++---------------- .github/workflows/shared-release-publish.yml | 1 - .../workflows/shared-testing-dotnetpack.yml | 1 - .github/workflows/shared-testing-linux.yml | 1 - .github/workflows/shared-testing-macos.yml | 1 - .../shared-testing-windows-playwright.yml | 1 - .../shared-testing-windows-trim-aot.yml | 1 - .github/workflows/shared-testing-windows.yml | 1 - 8 files changed, 13 insertions(+), 106 deletions(-) diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml index 67301cddc..e6935f117 100644 --- a/.github/actions/download-native-binaries/action.yml +++ b/.github/actions/download-native-binaries/action.yml @@ -6,110 +6,36 @@ inputs: description: Artifact naming mode required: true default: testing - target-root: description: Root path where normalized native artifacts should be written required: false default: "" - current-runner-only: - description: Only download artifacts matching the current OS/arch - required: false - default: "false" - runs: using: composite steps: - - - name: Resolve Runner Platform - id: resolve-runner + - name: Resolve Native Artifact Settings + id: resolve-native-artifact-settings shell: bash run: | set -euo pipefail - os="$RUNNER_OS" - arch="$RUNNER_ARCH" - - case "$os" in - Windows) - lib="windows" - ;; - Linux) - lib="linux" - ;; - macOS) - lib="osx" - ;; - *) - echo "Unsupported OS: $os" - exit 1 - ;; - esac + artifact_type="${{ inputs.artifact-type }}" + input_root="${{ inputs.target-root }}" - case "$arch" in - X64|x64) - arch="x64" + case "$artifact_type" in + testing) + pattern="native-testing-*" ;; - ARM64|arm64) - arch="arm64" + release) + pattern="native-*" ;; *) - echo "Unsupported arch: $arch" + echo "Unsupported artifact-type: $artifact_type" exit 1 ;; esac - echo "lib=$lib" >> "$GITHUB_OUTPUT" - echo "arch=$arch" >> "$GITHUB_OUTPUT" - - - - name: Resolve Native Artifact Settings - id: resolve-native-artifact-settings - shell: bash - run: | - set -euo pipefail - - artifact_type="${{ inputs.artifact-type }}" - input_root="${{ inputs.target-root }}" - current_only="${{ inputs.current-runner-only }}" - - lib="${{ steps.resolve-runner.outputs.lib }}" - arch="${{ steps.resolve-runner.outputs.arch }}" - - if [ "$current_only" = "true" ]; then - case "$artifact_type" in - testing) - artifact_name="native-testing-${lib}-${arch}" - ;; - release) - artifact_name="native-${lib}-${arch}" - ;; - *) - echo "Unsupported artifact-type: $artifact_type" - exit 1 - ;; - esac - - echo "mode=name" >> "$GITHUB_OUTPUT" - echo "artifact_name=$artifact_name" >> "$GITHUB_OUTPUT" - else - case "$artifact_type" in - testing) - pattern="native-testing-*" - ;; - release) - pattern="native-*" - ;; - *) - echo "Unsupported artifact-type: $artifact_type" - exit 1 - ;; - esac - - echo "mode=pattern" >> "$GITHUB_OUTPUT" - echo "pattern=$pattern" >> "$GITHUB_OUTPUT" - fi - if [ -n "$input_root" ]; then root="$input_root" elif [ "$artifact_type" = "testing" ]; then @@ -118,24 +44,14 @@ runs: root="artifacts/native" fi + echo "pattern=$pattern" >> "$GITHUB_OUTPUT" echo "root=$root" >> "$GITHUB_OUTPUT" - - - name: Download Native Build Artifacts (current runner only) - if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'name' }} + - name: Download Native Build Artifacts uses: actions/download-artifact@v8 with: - name: ${{ steps.resolve-native-artifact-settings.outputs.artifact_name }} path: artifacts/native - - - - name: Download Native Build Artifacts (all platforms) - if: ${{ steps.resolve-native-artifact-settings.outputs.mode == 'pattern' }} - uses: actions/download-artifact@v8 - with: pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }} - path: artifacts/native - - name: Normalize Native Artifacts shell: bash @@ -174,14 +90,12 @@ runs: copy_artifact "native-osx-arm64" "$ROOT/osx/arm64/Release" fi - - name: Verify Native Artifacts shell: bash run: | set -euo pipefail ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}" - EXPECTED=( "$ROOT/windows/x64/Release/InfiniFrame.Native.dll" "$ROOT/windows/x64/Release/WebView2Loader.dll" @@ -206,4 +120,4 @@ runs: exit 1 fi - echo "All native artifacts downloaded and verified." \ No newline at end of file + echo "All native artifacts downloaded and verified." diff --git a/.github/workflows/shared-release-publish.yml b/.github/workflows/shared-release-publish.yml index 1b9e50f4c..98869e080 100644 --- a/.github/workflows/shared-release-publish.yml +++ b/.github/workflows/shared-release-publish.yml @@ -60,7 +60,6 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: release - current-runner-only: false # We need to download artifacts from all runners - name: Verify Artifacts run: | diff --git a/.github/workflows/shared-testing-dotnetpack.yml b/.github/workflows/shared-testing-dotnetpack.yml index 5dae37094..7a11048c2 100644 --- a/.github/workflows/shared-testing-dotnetpack.yml +++ b/.github/workflows/shared-testing-dotnetpack.yml @@ -58,7 +58,6 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing - current-runner-only: false # We need to download from all runners - name: Restore run: dotnet restore InfiniFrame.GitHubActions.Release.slnf /p:NoWarn=NU1503 diff --git a/.github/workflows/shared-testing-linux.yml b/.github/workflows/shared-testing-linux.yml index 3e3c8f2ba..607e2f7a5 100644 --- a/.github/workflows/shared-testing-linux.yml +++ b/.github/workflows/shared-testing-linux.yml @@ -75,7 +75,6 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing - current-runner-only: true # Only download artifacts from the current runner - name: Compile GSettings schemas run: sudo glib-compile-schemas /usr/share/glib-2.0/schemas/ diff --git a/.github/workflows/shared-testing-macos.yml b/.github/workflows/shared-testing-macos.yml index 70eb618eb..273bd56d4 100644 --- a/.github/workflows/shared-testing-macos.yml +++ b/.github/workflows/shared-testing-macos.yml @@ -80,7 +80,6 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing - current-runner-only: true # Only download artifacts from the current runner - name: Restore run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 diff --git a/.github/workflows/shared-testing-windows-playwright.yml b/.github/workflows/shared-testing-windows-playwright.yml index 17ce98540..8f205f680 100644 --- a/.github/workflows/shared-testing-windows-playwright.yml +++ b/.github/workflows/shared-testing-windows-playwright.yml @@ -115,7 +115,6 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing - current-runner-only: true - name: NPM Install if: ${{ matrix.project.sourceFolder != '' }} diff --git a/.github/workflows/shared-testing-windows-trim-aot.yml b/.github/workflows/shared-testing-windows-trim-aot.yml index 5d85f0e18..5f6823dfd 100644 --- a/.github/workflows/shared-testing-windows-trim-aot.yml +++ b/.github/workflows/shared-testing-windows-trim-aot.yml @@ -68,7 +68,6 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing - current-runner-only: true # Only download artifacts from the current runner - name: Trim Analyzer Builds run: | diff --git a/.github/workflows/shared-testing-windows.yml b/.github/workflows/shared-testing-windows.yml index a28f600f7..93a4035c3 100644 --- a/.github/workflows/shared-testing-windows.yml +++ b/.github/workflows/shared-testing-windows.yml @@ -77,7 +77,6 @@ jobs: uses: ./.github/actions/download-native-binaries with: artifact-type: testing - current-runner-only: true # Only download artifacts from the current runner - name: Restore run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 From e93eba64a3140c4791679a819e95c7dd184491bc Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:48:15 +0200 Subject: [PATCH 69/86] Update `InfiniFrame.NativeBridge.csproj` to improve platform-specific native binary handling - Refine `NativeArch` conditions for better platform distinction (e.g., separate `x64` and `arm64` handling). - Standardize `` item attributes for clarity and consistency. - Ensure alignment of native binaries with their respective runtime paths. --- .../InfiniFrame.NativeBridge.csproj | 133 +++++++++--------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index 9a892cc47..1a7729c1f 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -6,9 +6,11 @@ true true - + x64 - $(Platform) + x64 + arm64 + arm64 windows linux @@ -59,96 +61,97 @@ - + + false + InfiniFrame.Native.dll + runtimes/win-x64/native/ + PreserveNewest + PreserveNewest + true + + > + false + WebView2Loader.dll + runtimes/win-x64/native/ + PreserveNewest + PreserveNewest + true + - + + false + InfiniFrame.Native.dll + runtimes/win-arm64/native/ + PreserveNewest + PreserveNewest + true + - + + false + WebView2Loader.dll + runtimes/win-arm64/native/ + PreserveNewest + PreserveNewest + true + - + + false + InfiniFrame.Native.so + runtimes/linux-x64/native/ + PreserveNewest + PreserveNewest + true + - + + false + InfiniFrame.Native.so + runtimes/linux-arm64/native/ + PreserveNewest + PreserveNewest + true + - + + false + InfiniFrame.Native.dylib + runtimes/osx-x64/native/ + PreserveNewest + PreserveNewest + true + - + + false + InfiniFrame.Native.dylib + runtimes/osx-arm64/native/ + PreserveNewest + PreserveNewest + true + From dd98c44095f2f0d42863776f68885a17af349f59 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 15:58:45 +0200 Subject: [PATCH 70/86] Update InfiniFrame.NativeBridge.csproj --- .../InfiniFrame.NativeBridge.csproj | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index 1a7729c1f..24ac76deb 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -6,8 +6,9 @@ true true - + x64 + x64 x64 arm64 arm64 @@ -63,7 +64,7 @@ false - InfiniFrame.Native.dll + InfiniFrame.Native.dll runtimes/win-x64/native/ PreserveNewest PreserveNewest @@ -75,7 +76,7 @@ false - WebView2Loader.dll + WebView2Loader.dll runtimes/win-x64/native/ PreserveNewest PreserveNewest @@ -87,7 +88,7 @@ false - InfiniFrame.Native.dll + InfiniFrame.Native.dll runtimes/win-arm64/native/ PreserveNewest PreserveNewest @@ -98,7 +99,7 @@ false - WebView2Loader.dll + WebView2Loader.dll runtimes/win-arm64/native/ PreserveNewest PreserveNewest @@ -110,7 +111,7 @@ false - InfiniFrame.Native.so + InfiniFrame.Native.so runtimes/linux-x64/native/ PreserveNewest PreserveNewest @@ -122,7 +123,7 @@ false - InfiniFrame.Native.so + InfiniFrame.Native.so runtimes/linux-arm64/native/ PreserveNewest PreserveNewest @@ -134,7 +135,7 @@ false - InfiniFrame.Native.dylib + InfiniFrame.Native.dylib runtimes/osx-x64/native/ PreserveNewest PreserveNewest @@ -146,7 +147,7 @@ false - InfiniFrame.Native.dylib + InfiniFrame.Native.dylib runtimes/osx-arm64/native/ PreserveNewest PreserveNewest From e48358b47acfcf68222cc80fb0aed34cd7f16f06 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 16:18:51 +0200 Subject: [PATCH 71/86] Add support for `NativeArch` parameter in workflows and refine `NativeArch` conditions in project file - Pass `NativeArch` as a matrix variable in Windows, macOS, and Linux workflows. - Update `InfiniFrame.NativeBridge.csproj` to conditionally use `NativeArch` when specified, improving platform-specific handling. --- .github/workflows/shared-testing-linux.yml | 4 +++- .github/workflows/shared-testing-macos.yml | 4 +++- .github/workflows/shared-testing-windows.yml | 4 +++- .../InfiniFrame.NativeBridge.csproj | 10 +++++----- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/shared-testing-linux.yml b/.github/workflows/shared-testing-linux.yml index 607e2f7a5..f2fa8b30b 100644 --- a/.github/workflows/shared-testing-linux.yml +++ b/.github/workflows/shared-testing-linux.yml @@ -80,7 +80,7 @@ jobs: run: sudo glib-compile-schemas /usr/share/glib-2.0/schemas/ - name: Restore - run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 + run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 /p:NativeArch=${{ matrix.arch }} - name: Build Release run: | @@ -88,6 +88,7 @@ jobs: --configuration Release \ --no-restore \ -p:SolutionDir=${{ github.workspace }}/ \ + -p:NativeArch=${{ matrix.arch }} \ -p:CMakePlatform=${{ matrix.arch }} \ -p:InfiniFrameSkipNativeBuild=true \ -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} @@ -172,6 +173,7 @@ jobs: --configuration Release \ --no-build \ --no-restore \ + -p:NativeArch=${{ matrix.arch }} \ -p:CMakePlatform=${{ matrix.arch }} \ -p:InfiniFrameSkipNativeBuild=true \ -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} diff --git a/.github/workflows/shared-testing-macos.yml b/.github/workflows/shared-testing-macos.yml index 273bd56d4..4869d6a50 100644 --- a/.github/workflows/shared-testing-macos.yml +++ b/.github/workflows/shared-testing-macos.yml @@ -82,7 +82,7 @@ jobs: artifact-type: testing - name: Restore - run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 + run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 /p:NativeArch=${{ matrix.arch }} - name: Build Release run: | @@ -90,6 +90,7 @@ jobs: --configuration Release \ --no-restore \ -p:SolutionDir=${{ github.workspace }}/ \ + -p:NativeArch=${{ matrix.arch }} \ -p:CMakePlatform=${{ matrix.arch }} \ -p:InfiniFrameSkipNativeBuild=true \ -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} @@ -119,6 +120,7 @@ jobs: --configuration Release \ --no-build \ --no-restore \ + -p:NativeArch=${{ matrix.arch }} \ -p:CMakePlatform=${{ matrix.arch }} \ -p:InfiniFrameSkipNativeBuild=true \ -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} diff --git a/.github/workflows/shared-testing-windows.yml b/.github/workflows/shared-testing-windows.yml index 93a4035c3..000262aca 100644 --- a/.github/workflows/shared-testing-windows.yml +++ b/.github/workflows/shared-testing-windows.yml @@ -79,7 +79,7 @@ jobs: artifact-type: testing - name: Restore - run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 + run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503 /p:NativeArch=${{ matrix.arch }} - name: Build Release shell: pwsh @@ -88,6 +88,7 @@ jobs: --configuration Release ` --no-restore ` /p:SolutionDir=$env:GITHUB_WORKSPACE/ ` + /p:NativeArch=${{ matrix.arch }} ` /p:CMakePlatform=${{ matrix.arch }} ` /p:InfiniFrameSkipNativeBuild=true ` /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} @@ -203,6 +204,7 @@ jobs: --configuration Release ` --no-build ` --no-restore ` + /p:NativeArch=${{ matrix.arch }} ` /p:CMakePlatform=${{ matrix.arch }} ` /p:InfiniFrameSkipNativeBuild=true ` /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index 24ac76deb..d5706f5e7 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -7,11 +7,11 @@ true - x64 - x64 - x64 - arm64 - arm64 + x64 + x64 + x64 + arm64 + arm64 windows linux From 307fe4e8c6e77d413aabaa042073e7807d9aff36 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 16:29:58 +0200 Subject: [PATCH 72/86] Remove deprecated `CMakePlatform` parameter from workflows - Eliminated unnecessary `/p:CMakePlatform` usage across Windows, macOS, and Linux workflows. - Ensured `NativeArch` parameter is used consistently for platform-specific configurations. --- .github/workflows/ci-codeql.yml | 4 ++-- .github/workflows/shared-testing-linux.yml | 2 -- .github/workflows/shared-testing-macos.yml | 2 -- .github/workflows/shared-testing-windows.yml | 2 -- 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml index a7dfd6d2d..db5c7bc3d 100644 --- a/.github/workflows/ci-codeql.yml +++ b/.github/workflows/ci-codeql.yml @@ -288,8 +288,8 @@ jobs: dotnet build src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj ` --configuration Release ` --no-restore ` - -p:SolutionDir="${{ github.workspace }}/" ` - -p:CMakePlatform=${{ matrix.arch }} + /p:NativeArch=${{ matrix.arch }} ` + /p:SolutionDir="${{ github.workspace }}/" - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/shared-testing-linux.yml b/.github/workflows/shared-testing-linux.yml index f2fa8b30b..49d9eeab5 100644 --- a/.github/workflows/shared-testing-linux.yml +++ b/.github/workflows/shared-testing-linux.yml @@ -89,7 +89,6 @@ jobs: --no-restore \ -p:SolutionDir=${{ github.workspace }}/ \ -p:NativeArch=${{ matrix.arch }} \ - -p:CMakePlatform=${{ matrix.arch }} \ -p:InfiniFrameSkipNativeBuild=true \ -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} @@ -174,7 +173,6 @@ jobs: --no-build \ --no-restore \ -p:NativeArch=${{ matrix.arch }} \ - -p:CMakePlatform=${{ matrix.arch }} \ -p:InfiniFrameSkipNativeBuild=true \ -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} diff --git a/.github/workflows/shared-testing-macos.yml b/.github/workflows/shared-testing-macos.yml index 4869d6a50..cfd954481 100644 --- a/.github/workflows/shared-testing-macos.yml +++ b/.github/workflows/shared-testing-macos.yml @@ -91,7 +91,6 @@ jobs: --no-restore \ -p:SolutionDir=${{ github.workspace }}/ \ -p:NativeArch=${{ matrix.arch }} \ - -p:CMakePlatform=${{ matrix.arch }} \ -p:InfiniFrameSkipNativeBuild=true \ -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} @@ -121,7 +120,6 @@ jobs: --no-build \ --no-restore \ -p:NativeArch=${{ matrix.arch }} \ - -p:CMakePlatform=${{ matrix.arch }} \ -p:InfiniFrameSkipNativeBuild=true \ -p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} diff --git a/.github/workflows/shared-testing-windows.yml b/.github/workflows/shared-testing-windows.yml index 000262aca..17da2199a 100644 --- a/.github/workflows/shared-testing-windows.yml +++ b/.github/workflows/shared-testing-windows.yml @@ -89,7 +89,6 @@ jobs: --no-restore ` /p:SolutionDir=$env:GITHUB_WORKSPACE/ ` /p:NativeArch=${{ matrix.arch }} ` - /p:CMakePlatform=${{ matrix.arch }} ` /p:InfiniFrameSkipNativeBuild=true ` /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} @@ -205,7 +204,6 @@ jobs: --no-build ` --no-restore ` /p:NativeArch=${{ matrix.arch }} ` - /p:CMakePlatform=${{ matrix.arch }} ` /p:InfiniFrameSkipNativeBuild=true ` /p:InfiniFrameEnableTestExports=${{ inputs.enable_test_exports }} From a03589c464c5e4a8a82c76b73611e84fe8a341b4 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 16:41:04 +0200 Subject: [PATCH 73/86] Standardize naming convention: Rename `gInfiniframeJsData` and `gInfiniframeJsSize` to `GInfiniframeJsData` and `GInfiniframeJsSize --- .../Native/.cmake/Embed.InfiniFrameJs.Impl.cmake | 8 ++++---- .../Native/Embedded/Embedded.h | 10 +++++----- .../Native/Embedded/InfiniFrameJs/InfiniFrameJs.h | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake index af672a6c4..07bebd806 100644 --- a/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake +++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake @@ -23,8 +23,8 @@ file(WRITE "${OUTPUT_HEADER}" "#pragma once // ReSharper disable once CppUnusedIncludeDirective #include -extern const unsigned char gInfiniframeJsData[]; -extern const size_t gInfiniframeJsSize; +extern const unsigned char GInfiniframeJsData[]; +extern const size_t GInfiniframeJsSize; ") # Source file @@ -35,7 +35,7 @@ file(WRITE "${OUTPUT_SOURCE}" "#include \"InfiniFrameJs.h\" // Generated at: ${GENERATED_AT} // ----------------------------------------------------------------------------- -alignas(16) const unsigned char gInfiniframeJsData[] = {${BYTES}}; +alignas(16) const unsigned char GInfiniframeJsData[] = {${BYTES}}; -const size_t gInfiniframeJsSize = sizeof(gInfiniframeJsData); +const size_t GInfiniframeJsSize = sizeof(GInfiniframeJsData); ") \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h index d5aa79e48..a4f36adc8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h @@ -7,12 +7,12 @@ namespace Embedded { inline const std::wstring& InfiniFrameJsUtf16() { static const std::wstring cached = [] { - const auto* src = reinterpret_cast(gInfiniframeJsData); + const auto* src = reinterpret_cast(GInfiniframeJsData); std::u16string temp; - temp.resize(simdutf::utf16_length_from_utf8(src, gInfiniframeJsSize)); + temp.resize(simdutf::utf16_length_from_utf8(src, GInfiniframeJsSize)); - const size_t written = simdutf::convert_utf8_to_utf16(src, gInfiniframeJsSize, temp.data()); + const size_t written = simdutf::convert_utf8_to_utf16(src, GInfiniframeJsSize, temp.data()); temp.resize(written); @@ -24,8 +24,8 @@ namespace Embedded { inline const std::string& InfiniFrameJsUtf8() { static const std::string cached = [] { - const auto* src = reinterpret_cast(gInfiniframeJsData); - return std::string(src, gInfiniframeJsSize); + const auto* src = reinterpret_cast(GInfiniframeJsData); + return std::string(src, GInfiniframeJsSize); }(); return cached; } diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h b/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h index 4b764b603..c8bc4c247 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h @@ -2,5 +2,5 @@ // ReSharper disable once CppUnusedIncludeDirective #include -extern const unsigned char gInfiniframeJsData[]; -extern const size_t gInfiniframeJsSize; +extern const unsigned char GInfiniframeJsData[]; // NOLINT(*-avoid-c-arrays) +extern const size_t GInfiniframeJsSize; From 4e22184940bd3c8daaec4ccea60528dec575f0cf Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 16:43:25 +0200 Subject: [PATCH 74/86] Standardize naming: Rename `cached` to `Cached` for consistency across `InfiniFrameJsUtf16` and `InfiniFrameJsUtf8` functions. Add section comments for clarity. --- .../Native/Embedded/Embedded.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h index a4f36adc8..3de4bb4d7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h @@ -1,12 +1,16 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "InfiniFrameJs.h" #include #include - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- namespace Embedded { inline const std::wstring& InfiniFrameJsUtf16() { - static const std::wstring cached = [] { + static const std::wstring Cached = [] { const auto* src = reinterpret_cast(GInfiniframeJsData); std::u16string temp; @@ -19,14 +23,14 @@ namespace Embedded { return std::wstring(temp.begin(), temp.end()); }(); - return cached; + return Cached; } inline const std::string& InfiniFrameJsUtf8() { - static const std::string cached = [] { + static const std::string Cached = [] { const auto* src = reinterpret_cast(GInfiniframeJsData); return std::string(src, GInfiniframeJsSize); }(); - return cached; + return Cached; } -} // namespace Embedded +} From 69bc23e1455e158c134a8ceb10873a145fb38e82 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 16:48:11 +0200 Subject: [PATCH 75/86] Update path to `CMakeLists.txt` in `bump_version.py` to match renamed directory structure --- .github/scripts/bump_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/bump_version.py b/.github/scripts/bump_version.py index 526ae5b27..cf4e49f8b 100644 --- a/.github/scripts/bump_version.py +++ b/.github/scripts/bump_version.py @@ -11,7 +11,7 @@ # Resolve paths from the repository root: .github/scripts -> repo root is three levels up. REPO_ROOT: Final[Path] = Path(__file__).parent.parent.parent FILE: Final[Path] = REPO_ROOT / "src" / "Directory.Build.props" -CMAKE_FILE: Final[Path] = REPO_ROOT / "src" / "InfiniFrame.Native" / "CMakeLists.txt" +CMAKE_FILE: Final[Path] = REPO_ROOT / "src" / "InfiniFrame.NativeBridge" / "Native" / "CMakeLists.txt" VERSION_PATTERN: Final[re.Pattern[str]] = re.compile(r"^\d+\.\d+\.\d+(-preview\.\d+)?$") BumpPart = Literal["major", "minor", "patch", "preview"] From eebe8a6684f4cd8db93b3cf623981849b12043ec Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 16:53:01 +0200 Subject: [PATCH 76/86] Add condition to skip NativeBridge restore on macOS in CodeQL workflow --- .github/workflows/ci-codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml index db5c7bc3d..76b3b3cda 100644 --- a/.github/workflows/ci-codeql.yml +++ b/.github/workflows/ci-codeql.yml @@ -279,6 +279,7 @@ jobs: config-file: ./.github/codeql-config.yml - name: Restore NativeBridge + if: matrix.os != 'macos-latest' run: | dotnet restore src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj /p:NoWarn=NU1503 From 41d73a076e57aad017e2f2ffd1b7f8dfeb1b6d72 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 17:19:21 +0200 Subject: [PATCH 77/86] Standardize headers: Replace documentation comments with section comments for `Imports` and `Code`. Use `auto` for clarity and simplify mutex locks. --- .../.cmake/Embed.InfiniFrameJs.Impl.cmake | 2 +- .../Platform/Linux/Core/WindowState.Gtk.cpp | 12 +++-- .../Native/Public/Exports/Exports.Dialog.cpp | 7 ++- .../Native/Public/Exports/Exports.Events.cpp | 7 ++- .../Public/Exports/Exports.Lifecycle.cpp | 7 ++- .../Native/Public/Exports/Exports.Memory.cpp | 7 ++- .../Public/Exports/Exports.Platform.cpp | 7 ++- .../Native/Public/Exports/Exports.Tests.cpp | 7 ++- .../Public/Exports/Exports.WindowCommands.cpp | 7 ++- .../Public/Exports/Exports.WindowState.cpp | 7 ++- .../Native/Public/Exports/Exports.h | 12 +++-- .../Native/Public/InfiniFrame.h | 35 ++++---------- .../Native/Public/InfiniFrameDialog.h | 16 +++---- .../Native/Public/InfiniFrameInitParams.h | 16 +++---- .../Native/Public/InfiniFrameWindow.h | 22 +++++---- .../Native/Public/InfiniFrameWindowImpl.h | 48 +++++++------------ .../Native/Types/Basic.h | 16 ++----- .../Native/Types/Callbacks.h | 12 ++--- .../Native/Types/Dialog.h | 9 ++-- .../Native/Types/DialogButtons.h | 6 +++ .../Native/Types/DialogIcon.h | 6 +++ .../Native/Types/DialogResult.h | 6 +++ .../Native/Types/Monitor.h | 6 +++ .../Native/Utils/Common.h | 8 ++-- .../Native/Utils/Dimensions.h | 8 +++- .../Native/Utils/ErrorCode.h | 12 +++-- .../Native/Utils/Event.h | 27 ++++------- .../Native/Utils/ExportGuards.h | 12 +++-- .../Native/Utils/Result.h | 10 ++-- .../Native/Utils/StringCopy.h | 10 ++-- .../Native/Utils/WindowsHandles.h | 11 +++-- 31 files changed, 210 insertions(+), 168 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake index 07bebd806..99647077b 100644 --- a/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake +++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake @@ -23,7 +23,7 @@ file(WRITE "${OUTPUT_HEADER}" "#pragma once // ReSharper disable once CppUnusedIncludeDirective #include -extern const unsigned char GInfiniframeJsData[]; +extern const unsigned char GInfiniframeJsData[]; // NOLINT(*-avoid-c-arrays) extern const size_t GInfiniframeJsSize; ") diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp index 8173f35e8..ab396dc93 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp @@ -1,12 +1,16 @@ #ifdef __linux__ - -#include "../Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +#include "Platform/Linux/Window.Gtk.Internal.h" #include #include -#include "../../../Utils/Common.h" - +#include "Utils/Common.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- void InfiniFrameWindow::GetTransparentEnabled(bool* enabled) const { *enabled = m_impl->_transparentEnabled; } diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp index 1030478ca..31ba132fe 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Dialog.cpp @@ -1,5 +1,10 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/Exports/Exports.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- extern "C" { EXPORTED InteropStatus InfiniFrame_ShowOpenFile( InfiniFrameWindow* inst, diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp index 669c81bf5..b124e901c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Events.cpp @@ -1,5 +1,10 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/Exports/Exports.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- extern "C" { EXPORTED InteropStatus InfiniFrame_AddCustomSchemeName(InfiniFrameWindow* instance, const AutoString scheme) { return RunWindowExportStatus(instance, [&](InfiniFrameWindow* window) { diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp index 00d065b0a..7da18814d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Lifecycle.cpp @@ -1,5 +1,10 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/Exports/Exports.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- extern "C" { EXPORTED InteropStatus InfiniFrame_ctor(InfiniFrameInitParams* initParams, InfiniFrameWindow** value) { ResetOut(value, static_cast(nullptr)); diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp index 582c48eb0..fd8396294 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Memory.cpp @@ -1,5 +1,10 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/Exports/Exports.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- extern "C" { EXPORTED InteropStatus InfiniFrame_FreeString(AutoString value) { return RunExportStatus([&] { diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp index 8207deb29..3befe9168 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Platform.cpp @@ -1,5 +1,10 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/Exports/Exports.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- extern "C" { #ifdef _WIN32 EXPORTED InteropStatus InfiniFrame_register_win32(const HINSTANCE hInstance) { diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp index b6b23d826..afcfb1938 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.Tests.cpp @@ -1,6 +1,11 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/InfiniFrame.h" #include "Utils/ExportGuards.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- #ifdef _WIN32 #define EXPORTED __declspec(dllexport) #else diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp index 9f9f0f6de..4d3819fd8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowCommands.cpp @@ -1,5 +1,10 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/Exports/Exports.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- extern "C" { EXPORTED InteropStatus InfiniFrame_Center(InfiniFrameWindow* instance) { return RunWindowExportStatus(instance, [](InfiniFrameWindow* window) { window->Center(); }); diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp index 6003e3ac0..da8760ee6 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.WindowState.cpp @@ -1,5 +1,10 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/Exports/Exports.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- extern "C" { EXPORTED InteropStatus InfiniFrame_GetTransparentEnabled(InfiniFrameWindow* instance, bool* enabled) { ResetOut(enabled, false); diff --git a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h index 87a47a7df..03cb07d37 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/Exports/Exports.h @@ -1,8 +1,7 @@ #pragma once - -#include "../InfiniFrame.h" -#include "../../Utils/ExportGuards.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #ifdef __linux__ #include #endif @@ -13,6 +12,11 @@ #define EXPORTED #endif +#include "Public/InfiniFrame.h" +#include "Utils/ExportGuards.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- using infiniframe::exports::EnsureNotNull; using infiniframe::exports::GetLastErrorMessageCopy; using infiniframe::exports::ResetOut; diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h index ad153aab7..5f00610bf 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrame.h @@ -1,31 +1,14 @@ #pragma once -/** - * @file InfiniFrame.h - * @brief Main header file for InfiniFrame native interop - * - * This file provides unified access to all InfiniFrame types and classes. - * It is the primary include file for C API consumers. - */ - -// --------------------------------------------------------------------------------------------------------------------- -// Core Types -// --------------------------------------------------------------------------------------------------------------------- - -#include "../Types/Basic.h" -#include "../Types/Dialog.h" -#include "../Types/Callbacks.h" -#include "InfiniFrameInitParams.h" - // --------------------------------------------------------------------------------------------------------------------- -// Core Classes +// Imports // --------------------------------------------------------------------------------------------------------------------- +#include "Public/InfiniFrameInitParams.h" +#include "Public/InfiniFrameWindow.h" +#include "Public/InfiniFrameDialog.h" -#include "InfiniFrameWindow.h" -#include "InfiniFrameDialog.h" - -// --------------------------------------------------------------------------------------------------------------------- -// Utilities -// --------------------------------------------------------------------------------------------------------------------- +#include "Types/Basic.h" +#include "Types/Dialog.h" +#include "Types/Callbacks.h" -#include "../Utils/Common.h" -#include "../Utils/Event.h" +#include "Utils/Common.h" +#include "Utils/Event.h" diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h index 61b59d1f5..cb50c9d7f 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameDialog.h @@ -1,16 +1,16 @@ #pragma once -/** - * @file InfiniFrameDialog.h - * @brief Dialog handlers for file/folder operations and messages - */ - -#include "../Types/Basic.h" -#include "../Types/Dialog.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #ifdef __APPLE__ #include #endif +#include "Types/Basic.h" +#include "Types/Dialog.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- class InfiniFrameWindow; // forward declaration /** diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h index d69b069cb..030d73e2c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameInitParams.h @@ -1,12 +1,12 @@ #pragma once -/** - * @file InfiniFrameInitParams.h - * @brief Window initialization parameters - */ - -#include "../Types/Basic.h" -#include "../Types/Callbacks.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +#include "Types/Basic.h" +#include "Types/Callbacks.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- class InfiniFrameWindow; // Forward declaration /** diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h index 86ae9cbfd..dd789524c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindow.h @@ -1,14 +1,11 @@ #pragma once -/** - * @file InfiniFrameWindow.h - * @brief Main window class for InfiniFrame - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #ifdef _WIN32 #include #include #include -class WinToastHandler; #endif #ifdef __APPLE__ @@ -30,10 +27,15 @@ class WinToastHandler; #include #include -#include "../Types/Basic.h" -#include "../Types/Dialog.h" -#include "../Types/Callbacks.h" - +#include "Types/Basic.h" +#include "Types/Dialog.h" +#include "Types/Callbacks.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +#ifdef _WIN32 +class WinToastHandler; +#endif class InfiniFrameDialog; struct InfiniFrameInitParams; diff --git a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h index 2cfe71e1e..97eb28c2a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h +++ b/src/InfiniFrame.NativeBridge/Native/Public/InfiniFrameWindowImpl.h @@ -1,32 +1,23 @@ #pragma once -/** - * @file InfiniFrameWindowImpl.h - * @brief Shared state for all platform InfiniFrameWindow::Impl structs. - * - * This is an INTERNAL header — included only by platform Window.cpp/.mm files, - * never by consumers of InfiniFrame. It defines the fields that are identical - * across Windows, Linux, and macOS implementations. - * - * Each platform defines: - * - * struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { ... platform handles ... }; - */ - -#include "../Types/Basic.h" -#include "../Types/Callbacks.h" -#include "InfiniFrameDialog.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include #include +#include "Types/Basic.h" +#include "Types/Callbacks.h" +#include "Public/InfiniFrameDialog.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- class InfiniFrameWindow; struct InfiniFrameWindowImpl { - // -----------------------------------------------------------------------------------------------------------------= + // ----------------------------------------------------------------------------------------------------------------- // Callbacks - // -----------------------------------------------------------------------------------------------------------------= - + // ----------------------------------------------------------------------------------------------------------------- WebMessageReceivedCallback _webMessageReceivedCallback = nullptr; WebResourceRequestedCallback _customSchemeCallback = nullptr; ResizedCallback _resizedCallback = nullptr; @@ -39,10 +30,9 @@ struct InfiniFrameWindowImpl { FocusInCallback _focusInCallback = nullptr; FocusOutCallback _focusOutCallback = nullptr; - // -----------------------------------------------------------------------------------------------------------------= + // ----------------------------------------------------------------------------------------------------------------- // Feature flags - // -----------------------------------------------------------------------------------------------------------------= - + // ----------------------------------------------------------------------------------------------------------------- bool _transparentEnabled = false; bool _contextMenuEnabled = true; bool _zoomEnabled = true; @@ -56,10 +46,9 @@ struct InfiniFrameWindowImpl { bool _smoothScrollingEnabled = true; bool _ignoreCertificateErrorsEnabled = false; - // -----------------------------------------------------------------------------------------------------------------= - // String state (NativeString = std::wstring on Windows, std::string elsewhere) - // -----------------------------------------------------------------------------------------------------------------= - + // ----------------------------------------------------------------------------------------------------------------- + // String state + // ----------------------------------------------------------------------------------------------------------------- NativeString _windowTitle; NativeString _startUrl; NativeString _startString; @@ -69,10 +58,9 @@ struct InfiniFrameWindowImpl { std::vector _customSchemeNames; - // -----------------------------------------------------------------------------------------------------------------= + // ----------------------------------------------------------------------------------------------------------------- // Ownership - // -----------------------------------------------------------------------------------------------------------------= - + // ----------------------------------------------------------------------------------------------------------------- InfiniFrameWindow* _parent = nullptr; std::unique_ptr _dialog; }; diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Basic.h b/src/InfiniFrame.NativeBridge/Native/Types/Basic.h index d32e86710..ab3605974 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Basic.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Basic.h @@ -1,25 +1,17 @@ #pragma once -/** - * @file Basic.h - * @brief Basic type definitions for cross-platform interop - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include - // --------------------------------------------------------------------------------------------------------------------- -// Native String Type +// Code // --------------------------------------------------------------------------------------------------------------------- - #ifdef _WIN32 using NativeString = std::wstring; #else using NativeString = std::string; #endif -// --------------------------------------------------------------------------------------------------------------------- -// AutoString (C API Interop) -// --------------------------------------------------------------------------------------------------------------------- - #ifdef _WIN32 using AutoString = wchar_t*; using AutoStringConst = const wchar_t*; diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h b/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h index b2fac92d7..b6e6ca453 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h @@ -1,16 +1,12 @@ #pragma once -/** - * @file Callbacks.h - * @brief C-style callback type definitions for interop - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Basic.h" #include "Dialog.h" - // --------------------------------------------------------------------------------------------------------------------- -// C-style Callbacks (for C# interop) +// Code // --------------------------------------------------------------------------------------------------------------------- - /** @brief Generic parameterless action callback */ using ACTION = void (*)(); diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h b/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h index 335801c80..eff083764 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h @@ -1,11 +1,8 @@ #pragma once -/** - * @file Dialog.h - * @brief Dialog-related types and enums - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "DialogButtons.h" #include "DialogIcon.h" #include "DialogResult.h" #include "Monitor.h" - diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h index 44d5dea81..e2296092f 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogButtons.h @@ -1,5 +1,11 @@ #pragma once +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- enum class DialogButtons { Ok, OkCancel, diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h index 437a3536b..158607749 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogIcon.h @@ -1,5 +1,11 @@ #pragma once +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- enum class DialogIcon { Info, Warning, diff --git a/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h b/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h index f82827247..111b4f2ed 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/DialogResult.h @@ -1,5 +1,11 @@ #pragma once +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- enum class DialogResult { Cancel = -1, Ok, diff --git a/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h b/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h index f649ccd8d..f407ab12b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h +++ b/src/InfiniFrame.NativeBridge/Native/Types/Monitor.h @@ -1,5 +1,11 @@ #pragma once +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- struct Monitor { struct MonitorRect { int x, y; diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Common.h b/src/InfiniFrame.NativeBridge/Native/Utils/Common.h index 19e7c89cd..5e4cd6cd0 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Common.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Common.h @@ -1,9 +1,7 @@ #pragma once -/** - * @file Common.h - * @brief Compatibility umbrella for common utilities - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Dimensions.h" #include "ErrorCode.h" #include "Result.h" diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h b/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h index f371f8238..c8d3b6fb4 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Dimensions.h @@ -1,7 +1,11 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- inline constexpr int MaxWindowDimension = 10000; inline constexpr int MinWindowDimension = 50; inline constexpr int DefaultWindowWidth = 800; diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h index 787ea383d..5cf6fbebe 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ErrorCode.h @@ -1,8 +1,12 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- enum class ErrorCode { Success = 0, InvalidArgument, @@ -63,6 +67,4 @@ inline std::error_code make_error_code(const ErrorCode e) noexcept { return {static_cast(e), errorCategory()}; } -namespace std { - template <> struct is_error_code_enum : true_type {}; -} // namespace std +template <> struct std::is_error_code_enum : true_type {}; diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Event.h b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h index d7943c594..54f9db76c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Event.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h @@ -1,19 +1,14 @@ #pragma once -/** - * @file Event.h - * @brief Modern event handling system with thread safety - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include #include #include -#include - // --------------------------------------------------------------------------------------------------------------------- -// Event System +// Code // --------------------------------------------------------------------------------------------------------------------- - template class Event { public: using Handler = std::function; @@ -33,7 +28,7 @@ template class Event { * @return Token for unsubscribing */ [[nodiscard]] Token Subscribe(Handler handler) { - std::unique_lock lock(m_mutex); + std::unique_lock lock(m_mutex); const auto token = m_nextToken++; m_handlers.emplace(token, std::move(handler)); return token; @@ -44,7 +39,7 @@ template class Event { * @param token Token returned from Subscribe */ void Unsubscribe(Token token) { - std::unique_lock lock(m_mutex); + std::unique_lock lock(m_mutex); m_handlers.erase(token); } @@ -53,7 +48,7 @@ template class Event { * @param args Arguments to pass to handlers */ void Raise(Args... args) { - std::shared_lock lock(m_mutex); + std::shared_lock lock(m_mutex); for (const auto& [_, handler] : m_handlers) { if (handler) { handler(args...); @@ -66,7 +61,7 @@ template class Event { * @return true if at least one handler is subscribed */ [[nodiscard]] bool HasSubscribers() const { - std::shared_lock lock(m_mutex); + std::shared_lock lock(m_mutex); return !m_handlers.empty(); } @@ -74,7 +69,7 @@ template class Event { * @brief Clear all subscribers */ void Clear() { - std::unique_lock lock(m_mutex); + std::unique_lock lock(m_mutex); m_handlers.clear(); } @@ -84,10 +79,6 @@ template class Event { Token m_nextToken = 1; }; -// --------------------------------------------------------------------------------------------------------------------- -// Event Subscription Guard -// --------------------------------------------------------------------------------------------------------------------- - template class EventSubscription { public: using EventType = Event; diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h index d431502f0..537f25b7a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/ExportGuards.h @@ -1,17 +1,21 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include #include #include #include -#include "../Public/InfiniFrame.h" - #ifdef _WIN32 #include #endif +#include "Public/InfiniFrame.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- enum class InteropStatus : int { Success = 0, InvalidArgument = 22, @@ -22,7 +26,7 @@ enum class InteropStatus : int { namespace infiniframe::exports { namespace detail { inline thread_local std::string g_lastErrorMessage; - inline thread_local InteropStatus g_lastStatus = InteropStatus::Success; + inline thread_local auto g_lastStatus = InteropStatus::Success; inline void SetLastErrorCode(const InteropStatus status) noexcept { #ifdef _WIN32 diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/Result.h b/src/InfiniFrame.NativeBridge/Native/Utils/Result.h index 9942e19e9..7ed7361b9 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/Result.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/Result.h @@ -1,7 +1,11 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include -#include "ErrorCode.h" - +#include "Utils/ErrorCode.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- template using Result = std::expected; diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h b/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h index b61cee595..5a1355fec 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/StringCopy.h @@ -1,5 +1,7 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include #include @@ -7,11 +9,13 @@ #ifdef __linux__ #include #endif - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- #ifdef _WIN32 inline wchar_t* AllocateStringCopy(const std::wstring& str) { const size_t len = str.length(); - wchar_t* copy = new wchar_t[len + 1]; + auto* copy = new wchar_t[len + 1]; std::memcpy(copy, str.c_str(), (len + 1) * sizeof(wchar_t)); return copy; } diff --git a/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h b/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h index 87c0e2c82..9ed5445dd 100644 --- a/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h +++ b/src/InfiniFrame.NativeBridge/Native/Utils/WindowsHandles.h @@ -1,10 +1,15 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #ifdef _WIN32 - #include #include - +#endif +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +#ifdef _WIN32 struct HBRUSHDeleter { void operator()(void* h) const noexcept { if (h) From 01faf9053091662b7aae3de8afced9e2bcefadb7 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 17:25:01 +0200 Subject: [PATCH 78/86] Refine CodeQL workflow and improve native build lock handling - Increase `dotnet build` timeout to 45 minutes and simplify build command formatting. - Add timeout mechanism for native build lock to prevent indefinite waits. --- .github/workflows/ci-codeql.yml | 9 ++------- src/InfiniFrame.NativeBridge/native-build.ps1 | 6 ++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml index 76b3b3cda..9f5ccc816 100644 --- a/.github/workflows/ci-codeql.yml +++ b/.github/workflows/ci-codeql.yml @@ -279,18 +279,13 @@ jobs: config-file: ./.github/codeql-config.yml - name: Restore NativeBridge - if: matrix.os != 'macos-latest' run: | dotnet restore src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj /p:NoWarn=NU1503 - name: Build NativeBridge - shell: pwsh + timeout-minutes: 45 run: | - dotnet build src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj ` - --configuration Release ` - --no-restore ` - /p:NativeArch=${{ matrix.arch }} ` - /p:SolutionDir="${{ github.workspace }}/" + dotnet build src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj --configuration Release --no-restore /p:SolutionDir=${{ github.workspace }}/ /p:NativeArch=${{ matrix.arch }} - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 diff --git a/src/InfiniFrame.NativeBridge/native-build.ps1 b/src/InfiniFrame.NativeBridge/native-build.ps1 index 4027ce498..85af1774c 100644 --- a/src/InfiniFrame.NativeBridge/native-build.ps1 +++ b/src/InfiniFrame.NativeBridge/native-build.ps1 @@ -38,6 +38,8 @@ $EnableTestExportsCMakeValue = if ($EnableTestExports -ieq "true") { "ON" } else # LOCK (blocking, CI-safe, race-free) # ----------------------------------------------------------------------------------------------------------------- $LockFile = Join-Path $ArtifactsDir ".build.lock" +$LockTimeoutSeconds = 600 +$LockDeadline = (Get-Date).AddSeconds($LockTimeoutSeconds) $LockStream = $null @@ -45,6 +47,10 @@ try { # Wait until lock becomes available (prevents crash) while ($true) { + if ((Get-Date) -ge $LockDeadline) { + throw "Timed out after $LockTimeoutSeconds seconds waiting for native build lock at '$LockFile'." + } + try { $LockStream = New-Object System.IO.FileStream( $LockFile, From 6522cd2236c937f04d87c050ec2a85177dca6e41 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 17:31:26 +0200 Subject: [PATCH 79/86] Comment out macOS ARM64 matrix entry in CodeQL workflow --- .github/workflows/ci-codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml index 9f5ccc816..2464640f8 100644 --- a/.github/workflows/ci-codeql.yml +++ b/.github/workflows/ci-codeql.yml @@ -244,8 +244,8 @@ jobs: - os: windows-latest arch: x64 - - os: macos-latest - arch: arm64 +# - os: macos-latest +# arch: arm64 permissions: contents: read From f70bbcdfad7a3dbaecf20f6a5de05795a15cd880 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Mon, 18 May 2026 21:26:22 +0200 Subject: [PATCH 80/86] Update native clean process and remove redundant target condition - Simplified `CleanNative` target condition in `InfiniFrame.NativeBridge.csproj`. - Expanded `native-clean.ps1` script to include additional directories for cleanup. --- .../InfiniFrame.NativeBridge.csproj | 2 +- src/InfiniFrame.NativeBridge/native-clean.ps1 | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj index d5706f5e7..17a71ac77 100644 --- a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj +++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj @@ -170,7 +170,7 @@ - + diff --git a/src/InfiniFrame.NativeBridge/native-clean.ps1 b/src/InfiniFrame.NativeBridge/native-clean.ps1 index 542315978..a503e7e97 100644 --- a/src/InfiniFrame.NativeBridge/native-clean.ps1 +++ b/src/InfiniFrame.NativeBridge/native-clean.ps1 @@ -4,5 +4,12 @@ Write-Host "Cleaning native build directories..." Remove-Item -Recurse -Force "$RootDir/build" -ErrorAction SilentlyContinue Remove-Item -Recurse -Force "$RootDir/artifacts" -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force "$RootDir/Native/build" -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force "$RootDir/Native/build-clang-tidy" -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force "$RootDir/Native/cmake-build-debug-windows" -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force "$RootDir/Native/cmake-build-debug-linux" -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force "$RootDir/Native/cmake-build-release-windows" -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force "$RootDir/Native/cmake-build-release-linux" -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force "$RootDir/Native/packages" -ErrorAction SilentlyContinue Write-Host "Native clean complete." \ No newline at end of file From 24865cd880ab38075b2e48a1829b65c72da5d711 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Tue, 19 May 2026 09:14:20 +0200 Subject: [PATCH 81/86] Add cmake.xml --- src/InfiniFrame.NativeBridge/Native/.idea/cmake.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/InfiniFrame.NativeBridge/Native/.idea/cmake.xml diff --git a/src/InfiniFrame.NativeBridge/Native/.idea/cmake.xml b/src/InfiniFrame.NativeBridge/Native/.idea/cmake.xml new file mode 100644 index 000000000..6b28f1cd6 --- /dev/null +++ b/src/InfiniFrame.NativeBridge/Native/.idea/cmake.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file From abb8aba6524f08bb21c3ba48e64b1bb16d3ba605 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Tue, 19 May 2026 09:16:12 +0200 Subject: [PATCH 82/86] Add GDB debugger support to CLion Linux environment setup script --- scripts/clion-linux-environment.sh | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/scripts/clion-linux-environment.sh b/scripts/clion-linux-environment.sh index 15e2b390a..d4584728e 100644 --- a/scripts/clion-linux-environment.sh +++ b/scripts/clion-linux-environment.sh @@ -91,6 +91,21 @@ echo "Installing Clang toolchain (optional but recommended)..." sudo apt install -y clang libc++-dev libc++abi-dev || true +# ---------------------------------------------------------------------------------------------------------------------- +# GDB / WSL Debugging Support +# ---------------------------------------------------------------------------------------------------------------------- +echo "Installing GDB debugger support..." + +sudo apt install -y \ + gdb \ + gdbserver + +echo "GDB version:" +gdb --version || true + +echo "GDB path:" +which gdb || true + # ---------------------------------------------------------------------------------------------------------------------- # GTK / WebKit / Native deps # ---------------------------------------------------------------------------------------------------------------------- @@ -135,5 +150,12 @@ g++ --version || true echo "Clang version:" clang++ --version || true +echo "GDB version:" +gdb --version || true + +echo "" +echo "Setup complete!" + echo "" -echo "Setup complete!" \ No newline at end of file +echo "Recommended CLion debugger path:" +echo "/usr/bin/gdb" \ No newline at end of file From a51975cd999f7f2856bf9885f2e34bd7b0c89754 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Tue, 19 May 2026 09:21:28 +0200 Subject: [PATCH 83/86] Improve `Embed.InfiniFrameJs` handling: add auto-generation metadata, adjust includes, and update alignment logic. --- .../Native/.cmake/Embed.InfiniFrameJs.Impl.cmake | 13 +++++++++---- .../Native/Embedded/InfiniFrameJs/InfiniFrameJs.h | 6 ------ 2 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h diff --git a/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake index 99647077b..c8dbf964f 100644 --- a/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake +++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake @@ -19,7 +19,12 @@ endforeach() string(TIMESTAMP GENERATED_AT "%Y-%m-%d %H:%M:%S UTC" UTC) # Header file -file(WRITE "${OUTPUT_HEADER}" "#pragma once +file(WRITE "${OUTPUT_HEADER}" "// ----------------------------------------------------------------------------- +// Auto-generated file. Do not edit manually. +// Generated at: ${GENERATED_AT} +// ----------------------------------------------------------------------------- +#pragma once + // ReSharper disable once CppUnusedIncludeDirective #include @@ -28,13 +33,13 @@ extern const size_t GInfiniframeJsSize; ") # Source file -file(WRITE "${OUTPUT_SOURCE}" "#include \"InfiniFrameJs.h\" - -// ----------------------------------------------------------------------------- +file(WRITE "${OUTPUT_SOURCE}" "// ----------------------------------------------------------------------------- // Auto-generated file. Do not edit manually. // Generated at: ${GENERATED_AT} // ----------------------------------------------------------------------------- +#include \"Embedded/InfiniFrameJs/InfiniFrameJs.h\" + alignas(16) const unsigned char GInfiniframeJsData[] = {${BYTES}}; const size_t GInfiniframeJsSize = sizeof(GInfiniframeJsData); diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h b/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h deleted file mode 100644 index c8bc4c247..000000000 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -// ReSharper disable once CppUnusedIncludeDirective -#include - -extern const unsigned char GInfiniframeJsData[]; // NOLINT(*-avoid-c-arrays) -extern const size_t GInfiniframeJsSize; From 4ec7bcd860b49c1d26f90b6743618d7937388f46 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Tue, 19 May 2026 09:22:55 +0200 Subject: [PATCH 84/86] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e7eadd063..8a1c6c100 100644 --- a/.gitignore +++ b/.gitignore @@ -355,6 +355,7 @@ healthchecksdb /src/InfiniFrame.NativeBridge/Native/cmake-build-release-linux/ /src/InfiniFrame.NativeBridge/Native/cmake-build-release-windows/ /src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.cpp +/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h # wwwroot folders from js web based projects /examples/InfiniFrameExample.WebApp.React/wwwroot/ From 103c22c4e3f531c9e749ed5ed8e80003a19f109c Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Tue, 19 May 2026 09:48:49 +0200 Subject: [PATCH 85/86] Standardize includes and remove redundant platform-specific guards in Linux codebase. --- .../Native/Embedded/Embedded.h | 2 +- .../Platform/Linux/Core/UiDispatcher.Gtk.cpp | 13 +++++++------ .../Platform/Linux/Core/WindowCore.Gtk.cpp | 15 ++++++++------- .../Platform/Linux/Core/WindowEvents.Gtk.cpp | 15 ++++++++------- .../Linux/Core/WindowInitialization.Gtk.cpp | 15 ++++++++------- .../Platform/Linux/Core/WindowLifecycle.Gtk.cpp | 13 +++++++------ .../Platform/Linux/Core/WindowSignals.Gtk.cpp | 13 +++++++------ .../Platform/Linux/Core/WindowState.Gtk.cpp | 8 ++------ .../Native/Platform/Linux/Dialog.cpp | 15 +++++++-------- .../Platform/Linux/WebKit/WebKit.Gtk.Internal.h | 8 ++++++-- .../Linux/WebKit/WebKitCustomSchemes.Gtk.cpp | 17 +++++++++-------- .../Platform/Linux/WebKit/WebKitHost.Gtk.cpp | 17 +++++++++-------- .../Linux/WebKit/WebKitMessaging.Gtk.cpp | 15 ++++++++------- .../Linux/WebKit/WebKitSettings.Gtk.cpp | 15 ++++++++------- .../Native/Platform/Linux/Window.Gtk.Internal.h | 9 ++++++--- 15 files changed, 101 insertions(+), 89 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h index 3de4bb4d7..5c3d510eb 100644 --- a/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h +++ b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h @@ -2,7 +2,7 @@ // --------------------------------------------------------------------------------------------------------------------- // Imports // --------------------------------------------------------------------------------------------------------------------- -#include "InfiniFrameJs.h" +#include "Embedded/InfiniFrameJs/InfiniFrameJs.h" #include #include // --------------------------------------------------------------------------------------------------------------------- diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp index 22b0d7e00..03680e670 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/UiDispatcher.Gtk.cpp @@ -1,10 +1,13 @@ -#ifdef __linux__ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include -#include "../Window.Gtk.Internal.h" - +#include "Platform/Linux/Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- namespace { std::mutex invokeLockMutex; @@ -34,5 +37,3 @@ void InfiniFrameWindow::Invoke(const ACTION callback) { std::unique_lock uLock(invokeLockMutex); waitInfo.completionNotifier.wait(uLock, [&] { return waitInfo.isCompleted; }); } - -#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp index a0b0a6b65..fd9fb7817 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowCore.Gtk.cpp @@ -1,10 +1,13 @@ -#ifdef __linux__ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include -#include "../Window.Gtk.Internal.h" - +#include "Platform/Linux/Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) : m_impl(std::make_unique()) { XInitThreads(); @@ -44,6 +47,4 @@ InfiniFrameWindow::InfiniFrameWindow(InfiniFrameInitParams* initParams) InfiniFrameWindow::~InfiniFrameWindow() { notify_uninit(); gtk_widget_destroy(m_impl->_window); -} - -#endif +} \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp index b8e890e7c..dfcb4b017 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowEvents.Gtk.cpp @@ -1,7 +1,10 @@ -#ifdef __linux__ - -#include "../Window.Gtk.Internal.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +#include "Platform/Linux/Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- InfiniFrameDialog* InfiniFrameWindow::GetDialog() const { return m_impl->_dialog.get(); } @@ -144,6 +147,4 @@ void InfiniFrameWindow::InvokeMinimized() const noexcept { } m_impl->_minimizedCallback(); -} - -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp index 4220dca51..246a1018b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowInitialization.Gtk.cpp @@ -1,11 +1,14 @@ -#ifdef __linux__ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include -#include "../../../Public/InfiniFrameDialog.h" -#include "../Window.Gtk.Internal.h" - +#include "Public/InfiniFrameDialog.h" +#include "Platform/Linux/Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- gboolean on_configure_event(GtkWidget* widget, GdkEvent* event, gpointer self); gboolean on_window_state_event(GtkWidget* widget, GdkEventWindowState* event, gpointer self); gboolean on_widget_deleted(GtkWidget* widget, GdkEvent* event, gpointer self); @@ -168,5 +171,3 @@ void InfiniFrameWindow::Impl::ConnectWebViewSignals(InfiniFrameWindow* window) { g_signal_connect(G_OBJECT(_webview), "permission-request", G_CALLBACK(on_permission_request), window); } - -#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp index 270372442..bb7c479b0 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowLifecycle.Gtk.cpp @@ -1,9 +1,12 @@ -#ifdef __linux__ - -#include "../Window.Gtk.Internal.h" - + // --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include +#include "Platform/Linux/Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- void InfiniFrameWindow::Center() { gint windowWidth, windowHeight; gtk_window_get_size(GTK_WINDOW(m_impl->_window), &windowWidth, &windowHeight); @@ -65,5 +68,3 @@ void InfiniFrameWindow::WaitForExit() { void InfiniFrameWindow::CloseWebView() { // Not implemented on Linux } - -#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp index 7434c7af5..9e83ed3e0 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowSignals.Gtk.cpp @@ -1,9 +1,12 @@ -#ifdef __linux__ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include -#include "../Window.Gtk.Internal.h" - +#include "Platform/Linux/Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- namespace { bool linux_webview_diagnostics_enabled() { const char* value = g_getenv("INFINIFRAME_LINUX_WEBVIEW_DIAGNOSTICS"); @@ -166,5 +169,3 @@ void on_webview_size_allocate(GtkWidget* widget, GtkAllocation* allocation, gpoi allocation ? allocation->height : -1 ); } - -#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp index ab396dc93..e0337e3d7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Core/WindowState.Gtk.cpp @@ -1,13 +1,11 @@ -#ifdef __linux__ // --------------------------------------------------------------------------------------------------------------------- // Imports // --------------------------------------------------------------------------------------------------------------------- -#include "Platform/Linux/Window.Gtk.Internal.h" - #include #include #include "Utils/Common.h" +#include "Platform/Linux/Window.Gtk.Internal.h" // --------------------------------------------------------------------------------------------------------------------- // Code // --------------------------------------------------------------------------------------------------------------------- @@ -324,6 +322,4 @@ void InfiniFrameWindow::SetTransparentEnabled(const bool enabled) { color.alpha = enabled ? 0 : 1; webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(m_impl->_webview), &color); } -} - -#endif +} \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp index acee85cd7..1f7ccc5cd 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp @@ -1,12 +1,12 @@ -#ifdef __linux__ -/** - * @file Dialog.cpp (Linux) - * @brief Linux implementation of InfiniFrameDialog using GTK3 file-chooser and message dialogs - */ - -#include "Public/InfiniFrameDialog.h" +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include +#include "Public/InfiniFrameDialog.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- /** @brief Distinguishes which GtkFileChooserAction to configure in ShowDialog */ enum DialogType { OpenFile, /// GTK_FILE_CHOOSER_ACTION_OPEN — select one or more files @@ -253,4 +253,3 @@ DialogResult InfiniFrameDialog::ShowMessage( return DialogResult::Cancel; } } -#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h index 4c74bbcb6..1791398ba 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKit.Gtk.Internal.h @@ -1,7 +1,11 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- namespace gtk_webkit { void HandleWebMessage( WebKitUserContentManager* contentManager, WebKitJavascriptResult* jsResult, gpointer userData diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp index 772237654..08fb18952 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitCustomSchemes.Gtk.cpp @@ -1,11 +1,14 @@ -#ifdef __linux__ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include -#include "../Window.Gtk.Internal.h" -#include "WebKit.Gtk.Internal.h" - +#include "Platform/Linux/Window.Gtk.Internal.h" +#include "Platform/Linux/WebKit/WebKit.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- namespace gtk_webkit { void HandleCustomSchemeRequest(WebKitURISchemeRequest* request, const gpointer user_data) { WebResourceRequestedCallback webResourceRequestedCallback = @@ -46,6 +49,4 @@ void InfiniFrameWindow::Impl::AddCustomSchemeHandlers() { reinterpret_cast(_customSchemeCallback), nullptr ); } -} - -#endif +} \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp index 23ac98077..a4829d224 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitHost.Gtk.cpp @@ -1,12 +1,15 @@ -#ifdef __linux__ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include -#include "../../../Embedded/Embedded.h" -#include "WebKit.Gtk.Internal.h" -#include "../Window.Gtk.Internal.h" - +#include "Embedded/Embedded.h" +#include "Platform/Linux/WebKit/WebKit.Gtk.Internal.h" +#include "Platform/Linux/Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- extern void on_webview_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data); extern gboolean on_webview_load_failed( WebKitWebView* web_view, WebKitLoadEvent load_event, gchar* failing_uri, GError* error, gpointer user_data @@ -77,5 +80,3 @@ void InfiniFrameWindow::Show(bool isAlreadyShown) { void InfiniFrameWindow::AttachWebView() { // On Linux, WebView is attached in Show() } - -#endif diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp index 7749628c6..981322b9a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitMessaging.Gtk.cpp @@ -1,12 +1,15 @@ -#ifdef __linux__ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include #include "Types/Basic.h" #include "Types/Callbacks.h" -#include "WebKit.Gtk.Internal.h" - +#include "Platform/Linux/WebKit/WebKit.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- namespace gtk_webkit { void HandleWebMessage( WebKitUserContentManager* contentManager, WebKitJavascriptResult* jsResult, const gpointer userData @@ -43,6 +46,4 @@ namespace gtk_webkit { } webkit_javascript_result_unref(jsResult); } -} // namespace gtk_webkit - -#endif +} diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp index 2d2e20fd1..40c0da1e8 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/WebKit/WebKitSettings.Gtk.cpp @@ -1,9 +1,12 @@ -#ifdef __linux__ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include -#include "../Window.Gtk.Internal.h" - +#include "Platform/Linux/Window.Gtk.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- void InfiniFrameWindow::Impl::set_webkit_settings() { WebKitSettings* settings = webkit_settings_new_with_settings( "allow_modal_dialogs", TRUE, "allow_top_navigation_to_data_urls", TRUE, "allow_universal_access_from_file_urls", @@ -93,6 +96,4 @@ void InfiniFrameWindow::Impl::set_webkit_customsettings(WebKitSettings* settings g_free(propertyName); } } catch (const simdjson::simdjson_error&) {} -} - -#endif +} \ No newline at end of file diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h index cf31e2943..0be61c9d7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.Gtk.Internal.h @@ -1,14 +1,17 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include - #include #include #include "Public/InfiniFrameWindow.h" #include "Public/InfiniFrameWindowImpl.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { GtkWidget* _window = nullptr; GtkWidget* _webview = nullptr; From 7bda3e88c63359a6d448afa9d35adda4751f6506 Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Tue, 19 May 2026 10:05:54 +0200 Subject: [PATCH 86/86] Standardize headers in Windows codebase: replace documentation comments with section comments for `Imports` and `Code`, adjust include paths for consistency. --- .../Windows/Core/UiDispatcher.Win32.cpp | 8 ++++++- .../Windows/Core/WindowCore.Win32.cpp | 11 +++++++--- .../Windows/Core/WindowEncoding.Win32.cpp | 12 ++++++----- .../Windows/Core/WindowEvents.Win32.cpp | 21 ++++++++++++------- .../Windows/Core/WindowLifecycle.Win32.cpp | 11 +++++++--- .../Windows/Core/WindowOwnership.Win32.cpp | 9 ++++++-- .../Windows/Core/WindowProc.Win32.cpp | 11 +++++++--- .../Windows/Core/WindowState.Win32.cpp | 12 +++++++---- .../Windows/Core/WindowStorage.Win32.cpp | 9 ++++++-- .../Windows/Core/WindowTracing.Win32.cpp | 18 +++++++++++++++- .../Native/Platform/Windows/DarkMode.cpp | 9 ++++++-- .../Native/Platform/Windows/DarkMode.h | 15 ++++++------- .../Native/Platform/Windows/Dialog.cpp | 12 +++++------ .../Native/Platform/Windows/ToastHandler.h | 13 ++++++------ .../Windows/WebView/WebView2Attach.Win32.cpp | 11 +++++++--- .../WebView/WebView2Controller.Win32.cpp | 9 ++++++-- .../Windows/WebView/WebView2Host.Win32.cpp | 9 ++++++-- .../Windows/WebView/WebView2Runtime.Win32.cpp | 12 +++++++---- .../Platform/Windows/Window.Win32.Context.h | 10 ++++++--- .../Platform/Windows/Window.Win32.Internal.h | 9 ++++++-- 20 files changed, 160 insertions(+), 71 deletions(-) diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp index 142b8c069..81ccfa54c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/UiDispatcher.Win32.cpp @@ -1,6 +1,12 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "chrono" -#include "../Window.Win32.Context.h" +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- void InfiniFrameWindow::WaitForExit() { auto* impl = m_impl.get(); ApplyPendingOwnerWindow(impl, L"wait_for_exit"); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowCore.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowCore.Win32.cpp index 498078aaf..dc13e6730 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowCore.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowCore.Win32.cpp @@ -1,6 +1,11 @@ -#include "../../../Utils/Common.h" -#include "../Window.Win32.Context.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +#include "Utils/Common.h" +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- static_assert(sizeof(wchar_t) == sizeof(char16_t)); const wchar_t* CLASS_NAME = L"InfiniFrame"; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp index 8db804df4..fa35407f7 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEncoding.Win32.cpp @@ -1,11 +1,13 @@ -#include -#include +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include - #include -#include "../Window.Win32.Context.h" - +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- std::wstring Utf8ToWide(const AutoString source) { if (source == nullptr) return {}; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp index f23b8b632..679ded74d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowEvents.Win32.cpp @@ -1,7 +1,12 @@ -#include "../Window.Win32.Internal.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include +#include "Platform/Windows/Window.Win32.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- BOOL MonitorEnum(const HMONITOR monitor, HDC, LPRECT, const LPARAM arg) { auto callback = reinterpret_cast(arg); UINT dpiX, dpiY; @@ -25,14 +30,14 @@ BOOL MonitorEnum(const HMONITOR monitor, HDC, LPRECT, const LPARAM arg) { void InfiniFrameWindow::ShowNotification(AutoString title, AutoString body) { std::wstring wideTitle = ToUTF16String(title); std::wstring wideBody = ToUTF16String(body); - if (m_impl->_notificationsEnabled && WinToastLib::WinToast::isCompatible()) { - WinToastLib::WinToastTemplate toast = - WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::ImageAndText02); - toast.setTextField(wideTitle.c_str(), WinToastLib::WinToastTemplate::FirstLine); - toast.setTextField(wideBody.c_str(), WinToastLib::WinToastTemplate::SecondLine); + if (m_impl->_notificationsEnabled && WinToast::isCompatible()) { + WinToastTemplate toast = + WinToastTemplate(WinToastTemplate::ImageAndText02); + toast.setTextField(wideTitle.c_str(), WinToastTemplate::FirstLine); + toast.setTextField(wideBody.c_str(), WinToastTemplate::SecondLine); if (!m_impl->_iconFileName.empty()) toast.setImagePath(m_impl->_iconFileName); - WinToastLib::WinToast::instance()->showToast(toast, m_impl->_toastHandler.get()); + WinToast::instance()->showToast(toast, m_impl->_toastHandler.get()); } } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp index c225508e5..327e0efdc 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowLifecycle.Win32.cpp @@ -1,8 +1,13 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include -#include "../DarkMode.h" -#include "../Window.Win32.Context.h" - +#include "Platform/Windows/DarkMode.h" +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- using namespace WinToastLib; LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowOwnership.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowOwnership.Win32.cpp index 349e8ea58..39f9941e1 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowOwnership.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowOwnership.Win32.cpp @@ -1,5 +1,10 @@ -#include "../Window.Win32.Context.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- InfiniFrameWindow* LookupWindowInstance(const HWND hwnd) { return reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); } diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp index cdda533e8..c360fdc53 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowProc.Win32.cpp @@ -1,6 +1,11 @@ -#include "../DarkMode.h" -#include "../Window.Win32.Context.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +#include "Platform/Windows/DarkMode.h" +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- // Central Win32 message dispatcher for an InfiniFrame top-level window. // This procedure coordinates native lifecycle events with managed/window context state: // - stores and retrieves the InfiniFrameWindow instance diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp index e60595b7f..43c58dc0d 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowState.Win32.cpp @@ -1,9 +1,13 @@ -#include "../Window.Win32.Internal.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include -#include "../../../Utils/Common.h" - +#include "Utils/Common.h" +#include "Platform/Windows/Window.Win32.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- void InfiniFrameWindow::Center() { int screenDpi = GetDpiForWindow(m_impl->_hWnd); int screenHeight = GetSystemMetricsForDpi(SM_CYSCREEN, screenDpi); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp index c79c407ed..d2777d8b3 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowStorage.Win32.cpp @@ -1,8 +1,13 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include -#include "../Window.Win32.Context.h" - +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- bool EnsureDirectoryWritable(const std::wstring& directoryPath) { if (directoryPath.empty()) return false; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp index 86343bc59..ba6991405 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Core/WindowTracing.Win32.cpp @@ -1,10 +1,26 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include #include #include -#include "../Window.Win32.Context.h" +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +/** + * Determines whether teardown trace logging is enabled in the system. + * + * This function typically checks a configuration setting or a runtime + * flag that specifies if detailed logging or tracing should be + * performed during the teardown phase of a system or application + * component. + * + * @return true if teardown trace logging is enabled, false otherwise. + */ bool IsTeardownTraceEnabled() { static const bool enabled = [] { wchar_t value[32] = {}; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp index dd012c76e..a39844573 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp @@ -1,7 +1,12 @@ -#include "DarkMode.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include +#include "Platform/Windows/DarkMode.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- using RtlGetNtVersionNumbers_f = void(WINAPI*)(LPDWORD, LPDWORD, LPDWORD); using SetWindowCompositionAttribute_f = HRESULT(WINAPI*)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h index c06657886..d74616e04 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h @@ -1,14 +1,11 @@ #pragma once -/** - * @file DarkMode.h - * @brief Win32 dark-mode helpers using undocumented UxTheme APIs - * - * Provides runtime detection and application of Windows dark mode for the - * non-client area (title bar, borders). All functions are noexcept and safe - * to call even when the underlying APIs are unavailable - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- /** @brief Detect available dark-mode APIs at runtime and cache the results. Must be called once at startup */ void InitDarkModeSupport() noexcept; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp index e08f6f62b..299956cf1 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp @@ -1,16 +1,16 @@ -/** - * @file Dialog.cpp (Windows) - * @brief Windows implementation of InfiniFrameDialog using IFileDialog (Vista+) and MessageBoxW - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include "Public/InfiniFrame.h" -#include #include #include #include #include #include +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- /** * @brief RAII wrapper that loads a DLL on construction and frees it on destruction. diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h index c12bab422..17b87b40c 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h @@ -1,13 +1,14 @@ #pragma once -/** - * @file ToastHandler.h - * @brief WinToast event handler that brings the window to the foreground on notification interaction - */ - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include + #include "Public/InfiniFrameWindow.h" #include "Dependencies/wintoastlib/wintoastlib.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- using namespace WinToastLib; /** diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp index 877b618eb..7147afcd4 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Attach.Win32.cpp @@ -1,11 +1,16 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include #include -#include "../../../Embedded/Embedded.h" -#include "../Window.Win32.Context.h" - +#include "Embedded/Embedded.h" +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- using namespace Microsoft::WRL; void InfiniFrameWindow::Show(const bool isAlreadyShown) { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp index eb0789bb6..25b25a07b 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Controller.Win32.cpp @@ -1,5 +1,10 @@ -#include "../Window.Win32.Context.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- using namespace Microsoft::WRL; void InfiniFrameWindow::RefitContent() { diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp index 3f5b7ded4..2027b475a 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Host.Win32.cpp @@ -1,5 +1,10 @@ -#include "../Window.Win32.Context.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- void InfiniFrameWindow::CloseWebView() { m_impl->_isClosingOrClosed.store(true, std::memory_order_release); const bool deferEnvironmentRelease = m_impl->_isWebView2Initializing && m_impl->_webviewController == nullptr; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp index 44e945410..a0c6320a6 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/WebView/WebView2Runtime.Win32.cpp @@ -1,9 +1,13 @@ -#include - -#include "../Window.Win32.Context.h" - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #pragma comment(lib, "Urlmon.lib") +#include +#include "Platform/Windows/Window.Win32.Context.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- bool InfiniFrameWindow::EnsureWebViewIsInstalled() { LPWSTR versionInfo = nullptr; HRESULT ensureInstalledResult = GetAvailableCoreWebView2BrowserVersionString(nullptr, &versionInfo); diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h index cacda332d..38fb3bd89 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Context.h @@ -1,5 +1,7 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include #include @@ -8,8 +10,10 @@ #include #include "Public/InfiniFrameWindow.h" -#include "Window.Win32.Internal.h" - +#include "Platform/Windows/Window.Win32.Internal.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- inline constexpr UINT WM_USER_INVOKE = WM_USER + 0x0002; extern std::atomic _hInstance; diff --git a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h index e69c1dc52..0281eb3ca 100644 --- a/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h +++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.Win32.Internal.h @@ -1,5 +1,7 @@ #pragma once - +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- #include #include @@ -9,8 +11,11 @@ #include "Public/InfiniFrameWindow.h" #include "Public/InfiniFrameWindowImpl.h" -#include "ToastHandler.h" +#include "Platform/Windows/ToastHandler.h" #include "Utils/Common.h" +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- struct InfiniFrameWindow::Impl : InfiniFrameWindowImpl { std::wstring _temporaryFilesPath;