e788e12b127eb9a6d2cd7816027bc83927fbe027
[reactos.git] / base / setup / lib / ntverrsrc.c
1 /*
2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: NT Version Resource Management API
5 * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
6 *
7 * NOTE 1: Adapted from Wine-synced dll/win32/version DLL.
8 * NOTE 2: We only deal with 32-bit PE executables.
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include "precomp.h"
14 #include <ndk/ldrtypes.h>
15 #include <ndk/ldrfuncs.h>
16
17 #include "ntverrsrc.h"
18
19 #define NDEBUG
20 #include <debug.h>
21
22
23 /* FUNCTIONS ****************************************************************/
24
25 NTSTATUS
26 NtGetVersionResource(
27 IN PVOID BaseAddress,
28 OUT PVOID* Resource,
29 OUT PULONG ResourceSize OPTIONAL)
30 {
31 // #define RT_VERSION MAKEINTRESOURCE(16) // See winuser.h
32 #define VS_VERSION_INFO 1 // See psdk/verrsrc.h
33 #define VS_FILE_INFO RT_VERSION
34
35 NTSTATUS Status;
36 LDR_RESOURCE_INFO ResourceInfo;
37 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
38 PVOID Data = NULL;
39 ULONG Size = 0;
40
41 /* Try to find the resource */
42 ResourceInfo.Type = 16; // RT_VERSION;
43 ResourceInfo.Name = VS_VERSION_INFO; // MAKEINTRESOURCEW(VS_VERSION_INFO);
44 ResourceInfo.Language = 0; // Don't care about the language
45
46 Status = LdrFindResource_U(BaseAddress,
47 &ResourceInfo,
48 RESOURCE_DATA_LEVEL,
49 &ResourceDataEntry);
50 if (!NT_SUCCESS(Status))
51 {
52 DPRINT1("NtGetVersionResource: Version resource not found, Status 0x%08lx\n", Status);
53 return Status;
54 }
55
56 /* Access the resource */
57 Status = LdrAccessResource(BaseAddress,
58 ResourceDataEntry,
59 &Data,
60 &Size);
61 if (!NT_SUCCESS(Status))
62 {
63 DPRINT1("NtGetVersionResource: Cannot access Version resource, Status 0x%08lx\n", Status);
64 return Status;
65 }
66
67 *Resource = Data;
68 if (ResourceSize) *ResourceSize = Size;
69
70 return STATUS_SUCCESS;
71 }
72
73 /* NOTE: the xxx_STRUCT16 version differs by storing strings in ANSI, not in UNICODE */
74 typedef struct _VS_VERSION_INFO_STRUCT32
75 {
76 WORD wLength;
77 WORD wValueLength;
78 WORD wType; /* 1:Text, 0:Binary */
79 WCHAR szKey[1];
80 #if 0 /* variable length structure */
81 /* DWORD aligned */
82 BYTE Value[];
83 /* DWORD aligned */
84 VS_VERSION_INFO_STRUCT32 Children[];
85 #endif
86 } VS_VERSION_INFO_STRUCT32, *PVS_VERSION_INFO_STRUCT32;
87 typedef const VS_VERSION_INFO_STRUCT32 *PCVS_VERSION_INFO_STRUCT32;
88
89 #define DWORD_ALIGN( base, ptr ) \
90 ( (ULONG_PTR)(base) + ((((ULONG_PTR)(ptr) - (ULONG_PTR)(base)) + 3) & ~3) )
91
92 #define VersionInfo32_Value( ver ) \
93 DWORD_ALIGN( (ver), (ver)->szKey + wcslen((ver)->szKey) + 1 )
94
95 #define VersionInfo32_Children( ver ) \
96 (PCVS_VERSION_INFO_STRUCT32)( VersionInfo32_Value( ver ) + \
97 ( ( (ver)->wValueLength * \
98 ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
99
100 #define VersionInfo32_Next( ver ) \
101 (PVS_VERSION_INFO_STRUCT32)( (ULONG_PTR)ver + (((ver)->wLength + 3) & ~3) )
102
103 static PCVS_VERSION_INFO_STRUCT32
104 VersionInfo32_FindChild(
105 IN PCVS_VERSION_INFO_STRUCT32 info,
106 IN PCWSTR szKey,
107 IN UINT cbKey)
108 {
109 PCVS_VERSION_INFO_STRUCT32 child = VersionInfo32_Children(info);
110
111 while ((ULONG_PTR)child < (ULONG_PTR)info + info->wLength)
112 {
113 if (!_wcsnicmp(child->szKey, szKey, cbKey) && !child->szKey[cbKey])
114 return child;
115
116 if (child->wLength == 0) return NULL;
117 child = VersionInfo32_Next(child);
118 }
119
120 return NULL;
121 }
122
123 static NTSTATUS
124 VersionInfo32_QueryValue(
125 IN PCVS_VERSION_INFO_STRUCT32 info,
126 IN PCWSTR lpSubBlock,
127 OUT PVOID* lplpBuffer,
128 OUT PUINT puLen OPTIONAL,
129 OUT BOOL* pbText OPTIONAL)
130 {
131 PCWSTR lpNextSlash;
132
133 DPRINT("lpSubBlock : (%S)\n", lpSubBlock);
134
135 while (*lpSubBlock)
136 {
137 /* Find next path component */
138 for (lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++)
139 {
140 if (*lpNextSlash == '\\')
141 break;
142 }
143
144 /* Skip empty components */
145 if (lpNextSlash == lpSubBlock)
146 {
147 lpSubBlock++;
148 continue;
149 }
150
151 /* We have a non-empty component: search info for key */
152 info = VersionInfo32_FindChild(info, lpSubBlock, lpNextSlash - lpSubBlock);
153 if (!info)
154 {
155 if (puLen) *puLen = 0;
156 return STATUS_RESOURCE_TYPE_NOT_FOUND;
157 }
158
159 /* Skip path component */
160 lpSubBlock = lpNextSlash;
161 }
162
163 /* Return value */
164 *lplpBuffer = (PVOID)VersionInfo32_Value(info);
165 if (puLen)
166 *puLen = info->wValueLength;
167 if (pbText)
168 *pbText = info->wType;
169
170 return STATUS_SUCCESS;
171 }
172
173 NTSTATUS
174 NtVerQueryValue(
175 IN const VOID* pBlock,
176 IN PCWSTR lpSubBlock,
177 OUT PVOID* lplpBuffer,
178 OUT PUINT puLen)
179 {
180 PCVS_VERSION_INFO_STRUCT32 info = pBlock;
181
182 DPRINT("%s (%p, %S, %p, %p)\n", __FUNCTION__, pBlock, lpSubBlock, lplpBuffer, puLen);
183
184 if (!pBlock)
185 return FALSE;
186
187 if (!lpSubBlock || !*lpSubBlock)
188 lpSubBlock = L"\\";
189
190 return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen, NULL);
191 }
192
193 /* EOF */