1 /*
2 * PROJECT: ReactOS apisets
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Resolving the apiset to a ReactOS system dll
5 * COPYRIGHT: Copyright 2024 Mark Jansen <mark.jansen@reactos.org>
6 */
7
8 #include <ndk/umtypes.h>
9 #include <ndk/rtlfuncs.h>
10 #include "apisetsp.h"
11
12
13 const ULONGLONG API_ = (ULONGLONG)0x2D004900500041; /// L"API-"
14 const ULONGLONG EXT_ = (ULONGLONG)0x2D005400580045; /// L"EXT-";
15
16 WORD PrefixSize = sizeof(L"api-") - sizeof(WCHAR);
17 WORD ExtensionSize = sizeof(L".dll") - sizeof(WCHAR);
18
19
20 // The official prototype according to the Windows kit 8.1 is:
21 //NTSTATUS
22 //ApiSetResolveToHost (
23 // _In_ PCAPI_SET_NAMESPACE_ARRAY Schema,
24 // _In_ PCUNICODE_STRING FileNameIn,
25 // _In_opt_ PCUNICODE_STRING ParentName,
26 // _Out_ PBOOLEAN Resolved,
27 // _Out_ PUNICODE_STRING HostBinary
28 // );
29
30
31 NTSTATUS
ApiSetResolveToHost(_In_ DWORD ApisetVersion,_In_ PCUNICODE_STRING ApiToResolve,_Out_ PBOOLEAN Resolved,_Out_ PUNICODE_STRING Output)32 ApiSetResolveToHost(
33 _In_ DWORD ApisetVersion,
34 _In_ PCUNICODE_STRING ApiToResolve,
35 _Out_ PBOOLEAN Resolved,
36 _Out_ PUNICODE_STRING Output
37 )
38 {
39 if (ApiToResolve->Length < PrefixSize)
40 {
41 *Resolved = FALSE;
42 return STATUS_SUCCESS;
43 }
44
45 // Grab the first four chars from the string, converting the first 3 to uppercase
46 PWSTR ApiSetNameBuffer = ApiToResolve->Buffer;
47 ULONGLONG ApiSetNameBufferPrefix = ((ULONGLONG *)ApiSetNameBuffer)[0] & 0xFFFFFFDFFFDFFFDF;
48 // Check if it matches either 'api-' or 'ext-'
49 if (!(ApiSetNameBufferPrefix == API_ || ApiSetNameBufferPrefix == EXT_))
50 {
51 *Resolved = FALSE;
52 return STATUS_SUCCESS;
53 }
54
55 // If there is an extension, cut it off (we store apisets without extension)
56 UNICODE_STRING Tmp = *ApiToResolve;
57 const WCHAR *Extension = Tmp.Buffer + (Tmp.Length - ExtensionSize) / sizeof(WCHAR);
58 if (!_wcsnicmp(Extension, L".dll", ExtensionSize / sizeof(WCHAR)))
59 Tmp.Length -= ExtensionSize;
60
61 // Binary search the apisets
62 // Ideally we should use bsearch here, but that drags in another dependency and we do not want that here.
63 LONG UBnd = g_ApisetsCount - 1;
64 LONG LBnd = 0;
65 while (LBnd <= UBnd)
66 {
67 LONG Index = (UBnd - LBnd) / 2 + LBnd;
68
69 LONG result = RtlCompareUnicodeString(&Tmp, &g_Apisets[Index].Name, TRUE);
70 if (result == 0)
71 {
72 // Check if this version is included
73 if (g_Apisets[Index].dwOsVersions & ApisetVersion)
74 {
75 // Return a static string (does not have to be freed)
76 *Resolved = TRUE;
77 *Output = g_Apisets[Index].Target;
78 }
79 return STATUS_SUCCESS;
80 }
81 else if (result < 0)
82 {
83 UBnd = Index - 1;
84 }
85 else
86 {
87 LBnd = Index + 1;
88 }
89 }
90 *Resolved = FALSE;
91 return STATUS_SUCCESS;
92 }
93