xref: /reactos/base/setup/lib/utils/ntverrsrc.c (revision a6726659)
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 cchKey)
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, cchKey) && !child->szKey[cchKey])
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 */
194