xref: /reactos/base/applications/cmdutils/reg/query.c (revision 01c1091e)
1 /*
2  * Copyright 2016-2017, 2021 Hugh McMaster
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include <stdio.h>
20 #include "reg.h"
21 
22 static const WCHAR *reg_type_to_wchar(DWORD type)
23 {
24     int i, array_size = ARRAY_SIZE(type_rels);
25 
26     for (i = 0; i < array_size; i++)
27     {
28         if (type == type_rels[i].type)
29             return type_rels[i].name;
30     }
31 
32     return NULL;
33 }
34 
35 static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes)
36 {
37     WCHAR *buffer = NULL;
38     int i;
39 
40     switch (type)
41     {
42         case REG_SZ:
43         case REG_EXPAND_SZ:
44             buffer = heap_xalloc(size_bytes);
45             lstrcpyW(buffer, (WCHAR *)src);
46             break;
47         case REG_NONE:
48         case REG_BINARY:
49         {
50             WCHAR *ptr;
51             static const WCHAR fmt[] = {'%','0','2','X',0};
52 
53             buffer = heap_xalloc((size_bytes * 2 + 1) * sizeof(WCHAR));
54             ptr = buffer;
55             for (i = 0; i < size_bytes; i++)
56                 ptr += swprintf(ptr, 3, fmt, src[i]);
57             break;
58         }
59         case REG_DWORD:
60      /* case REG_DWORD_LITTLE_ENDIAN: */
61         case REG_DWORD_BIG_ENDIAN:
62         {
63             const int zero_x_dword = 10;
64             static const WCHAR fmt[] = {'0','x','%','x',0};
65 
66             buffer = heap_xalloc((zero_x_dword + 1) * sizeof(WCHAR));
67             swprintf(buffer, zero_x_dword + 1, fmt, *(DWORD *)src);
68             break;
69         }
70         case REG_MULTI_SZ:
71         {
72             const int two_wchars = 2 * sizeof(WCHAR);
73             DWORD tmp_size;
74             const WCHAR *tmp = (const WCHAR *)src;
75             int len, destindex;
76 
77             if (size_bytes <= two_wchars)
78             {
79                 buffer = heap_xalloc(sizeof(WCHAR));
80                 *buffer = 0;
81                 return buffer;
82             }
83 
84             tmp_size = size_bytes - two_wchars; /* exclude both null terminators */
85             buffer = heap_xalloc(tmp_size * 2 + sizeof(WCHAR));
86             len = tmp_size / sizeof(WCHAR);
87 
88             for (i = 0, destindex = 0; i < len; i++, destindex++)
89             {
90                 if (tmp[i])
91                     buffer[destindex] = tmp[i];
92                 else
93                 {
94                     buffer[destindex++] = '\\';
95                     buffer[destindex] = '0';
96                 }
97             }
98             buffer[destindex] = 0;
99             break;
100         }
101     }
102     return buffer;
103 }
104 
105 static const WCHAR newlineW[] = {'\n',0};
106 
107 static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size)
108 {
109     static const WCHAR fmt[] = {' ',' ',' ',' ','%','1',0};
110     WCHAR defval[32];
111     WCHAR *reg_data;
112 
113     if (value_name && value_name[0])
114         output_string(fmt, value_name);
115     else
116     {
117         LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval));
118         output_string(fmt, defval);
119     }
120     output_string(fmt, reg_type_to_wchar(type));
121 
122     if (data)
123     {
124         reg_data = reg_data_to_wchar(type, data, data_size);
125         output_string(fmt, reg_data);
126         heap_free(reg_data);
127     }
128     else
129     {
130         LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval));
131         output_string(fmt, defval);
132     }
133     output_string(newlineW);
134 }
135 
136 static unsigned int num_values_found = 0;
137 
138 static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse)
139 {
140     LONG rc;
141     DWORD max_data_bytes = 2048, data_size;
142     DWORD subkey_len;
143     DWORD type, path_len, i;
144     BYTE *data;
145     WCHAR fmt[] = {'%','1','\n',0};
146     WCHAR *subkey_name, *subkey_path;
147     HKEY subkey;
148 
149     data = heap_xalloc(max_data_bytes);
150 
151     for (;;)
152     {
153         data_size = max_data_bytes;
154         rc = RegQueryValueExW(key, value_name, NULL, &type, data, &data_size);
155         if (rc == ERROR_MORE_DATA)
156         {
157             max_data_bytes = data_size;
158             data = heap_xrealloc(data, max_data_bytes);
159         }
160         else break;
161     }
162 
163     if (rc == ERROR_SUCCESS)
164     {
165         output_string(fmt, path);
166         output_value(value_name, type, data, data_size);
167         output_string(newlineW);
168         num_values_found++;
169     }
170 
171     heap_free(data);
172 
173     if (!recurse)
174     {
175         if (rc == ERROR_FILE_NOT_FOUND)
176         {
177             if (value_name && *value_name)
178             {
179                 output_message(STRING_CANNOT_FIND);
180                 return 1;
181             }
182             output_string(fmt, path);
183             output_value(NULL, REG_SZ, NULL, 0);
184         }
185         return 0;
186     }
187 
188     subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
189 
190     path_len = lstrlenW(path);
191 
192     i = 0;
193     for (;;)
194     {
195         subkey_len = MAX_SUBKEY_LEN;
196         rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
197         if (rc == ERROR_SUCCESS)
198         {
199             subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
200             if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
201             {
202                 query_value(subkey, value_name, subkey_path, recurse);
203                 RegCloseKey(subkey);
204             }
205             heap_free(subkey_path);
206             i++;
207         }
208         else break;
209     }
210 
211     heap_free(subkey_name);
212     return 0;
213 }
214 
215 static int query_all(HKEY key, WCHAR *path, BOOL recurse)
216 {
217     LONG rc;
218     DWORD max_value_len = 256, value_len;
219     DWORD max_data_bytes = 2048, data_size;
220     DWORD subkey_len;
221     DWORD i, type, path_len;
222     WCHAR fmt[] = {'%','1','\n',0};
223     WCHAR fmt_path[] = {'%','1','\\','%','2','\n',0};
224     WCHAR *value_name, *subkey_name, *subkey_path;
225     BYTE *data;
226     HKEY subkey;
227 
228     output_string(fmt, path);
229 
230     value_name = heap_xalloc(max_value_len * sizeof(WCHAR));
231     data = heap_xalloc(max_data_bytes);
232 
233     i = 0;
234     for (;;)
235     {
236         value_len = max_value_len;
237         data_size = max_data_bytes;
238         rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size);
239         if (rc == ERROR_SUCCESS)
240         {
241             output_value(value_name, type, data, data_size);
242             i++;
243         }
244         else if (rc == ERROR_MORE_DATA)
245         {
246             if (data_size > max_data_bytes)
247             {
248                 max_data_bytes = data_size;
249                 data = heap_xrealloc(data, max_data_bytes);
250             }
251             else
252             {
253                 max_value_len *= 2;
254                 value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR));
255             }
256         }
257         else break;
258     }
259 
260     heap_free(data);
261     heap_free(value_name);
262 
263     if (i || recurse)
264         output_string(newlineW);
265 
266     subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
267 
268     path_len = lstrlenW(path);
269 
270     i = 0;
271     for (;;)
272     {
273         subkey_len = MAX_SUBKEY_LEN;
274         rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
275         if (rc == ERROR_SUCCESS)
276         {
277             if (recurse)
278             {
279                 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
280                 if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
281                 {
282                     query_all(subkey, subkey_path, recurse);
283                     RegCloseKey(subkey);
284                 }
285                 heap_free(subkey_path);
286             }
287             else output_string(fmt_path, path, subkey_name);
288             i++;
289         }
290         else break;
291     }
292 
293     heap_free(subkey_name);
294 
295     if (i && !recurse)
296         output_string(newlineW);
297 
298     return 0;
299 }
300 
301 int reg_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name,
302               BOOL value_empty, BOOL recurse)
303 {
304     HKEY key;
305     int ret;
306 
307     if (RegOpenKeyExW(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS)
308     {
309         output_message(STRING_CANNOT_FIND);
310         return 1;
311     }
312 
313     output_string(newlineW);
314 
315     if (value_name || value_empty)
316     {
317         ret = query_value(key, value_name, key_name, recurse);
318         if (recurse)
319             output_message(STRING_MATCHES_FOUND, num_values_found);
320     }
321     else
322         ret = query_all(key, key_name, recurse);
323 
324     RegCloseKey(key);
325 
326     return ret;
327 }
328