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