source: josm/trunk/src/org/openstreetmap/josm/tools/WinRegistry.java@ 14074

Last change on this file since 14074 was 13672, checked in by Don-vip, 6 years ago

fix recent SonarQube issues

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.lang.reflect.InvocationTargetException;
5import java.lang.reflect.Method;
6import java.nio.charset.StandardCharsets;
7import java.util.ArrayList;
8import java.util.Arrays;
9import java.util.Collections;
10import java.util.HashMap;
11import java.util.List;
12import java.util.Map;
13import java.util.prefs.Preferences;
14
15/**
16 * Utility class to access Window registry (read access only).
17 * As the implementation relies on internal JDK class {@code java.util.prefs.WindowsPreferences} and its native JNI
18 * method {@code Java_java_util_prefs_WindowsPreferences_WindowsRegQueryValueEx}, only String values (REG_SZ)
19 * are supported.
20 * Adapted from <a href="http://stackoverflow.com/a/6163701/2257172">StackOverflow</a>.
21 * @since 12217
22 */
23public final class WinRegistry {
24
25 /**
26 * Registry entries subordinate to this key define the preferences of the current user.
27 * These preferences include the settings of environment variables, data about program groups,
28 * colors, printers, network connections, and application preferences.
29 * See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724836(v=vs.85).aspx">Predefined Keys</a>
30 */
31 public static final int HKEY_CURRENT_USER = 0x80000001;
32
33 /**
34 * Registry entries subordinate to this key define the physical state of the computer, including data about the bus type,
35 * system memory, and installed hardware and software. It contains subkeys that hold current configuration data,
36 * including Plug and Play information (the Enum branch, which includes a complete list of all hardware that has ever been
37 * on the system), network logon preferences, network security information, software-related information (such as server
38 * names and the location of the server), and other system information.
39 * See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724836(v=vs.85).aspx">Predefined Keys</a>
40 */
41 public static final int HKEY_LOCAL_MACHINE = 0x80000002;
42
43 private static final long REG_SUCCESS = 0L;
44
45 private static final int KEY_READ = 0x20019;
46 private static final Preferences userRoot = Preferences.userRoot();
47 private static final Preferences systemRoot = Preferences.systemRoot();
48 private static final Class<? extends Preferences> userClass = userRoot.getClass();
49 private static final Method regOpenKey;
50 private static final Method regCloseKey;
51 private static final Method regQueryValueEx;
52 private static final Method regEnumValue;
53 private static final Method regQueryInfoKey;
54 private static final Method regEnumKeyEx;
55
56 private static boolean java11;
57
58 static {
59 regOpenKey = getDeclaredMethod("WindowsRegOpenKey", int.class, byte[].class, int.class);
60 regCloseKey = getDeclaredMethod("WindowsRegCloseKey", int.class);
61 regQueryValueEx = getDeclaredMethod("WindowsRegQueryValueEx", int.class, byte[].class);
62 regEnumValue = getDeclaredMethod("WindowsRegEnumValue", int.class, int.class, int.class);
63 regQueryInfoKey = getDeclaredMethod("WindowsRegQueryInfoKey1", int.class);
64 regEnumKeyEx = getDeclaredMethod("WindowsRegEnumKeyEx", int.class, int.class, int.class);
65 Utils.setObjectsAccessible(regOpenKey, regCloseKey, regQueryValueEx, regEnumValue, regQueryInfoKey, regEnumKeyEx);
66 }
67
68 private static Method getDeclaredMethod(String name, Class<?>... parameterTypes) {
69 try {
70 return userClass.getDeclaredMethod(name, parameterTypes);
71 } catch (NoSuchMethodException e) {
72 if (parameterTypes.length > 0 && parameterTypes[0] == int.class) {
73 // JDK-8198899: change of signature in Java 11. Old signature to drop when we switch to Java 11
74 Class<?>[] parameterTypesCopy = Utils.copyArray(parameterTypes);
75 parameterTypesCopy[0] = long.class;
76 java11 = true;
77 return getDeclaredMethod(name, parameterTypesCopy);
78 }
79 Logging.log(Logging.LEVEL_ERROR, "Unable to find WindowsReg method", e);
80 return null;
81 } catch (RuntimeException e) {
82 Logging.log(Logging.LEVEL_ERROR, "Unable to get WindowsReg method", e);
83 return null;
84 }
85 }
86
87 private static Number hkey(int key) {
88 return java11 ? ((Number) Long.valueOf(key)) : ((Number) Integer.valueOf(key));
89 }
90
91 private WinRegistry() {
92 // Hide default constructor for utilities classes
93 }
94
95 /**
96 * Read a value from key and value name
97 * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
98 * @param key key name
99 * @param valueName value name
100 * @return the value
101 * @throws IllegalArgumentException if hkey not HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
102 * @throws IllegalAccessException if Java language access control is enforced and the underlying method is inaccessible
103 * @throws InvocationTargetException if the underlying method throws an exception
104 */
105 public static String readString(int hkey, String key, String valueName)
106 throws IllegalAccessException, InvocationTargetException {
107 if (hkey == HKEY_LOCAL_MACHINE) {
108 return readString(systemRoot, hkey, key, valueName);
109 } else if (hkey == HKEY_CURRENT_USER) {
110 return readString(userRoot, hkey, key, valueName);
111 } else {
112 throw new IllegalArgumentException("hkey=" + hkey);
113 }
114 }
115
116 /**
117 * Read value(s) and value name(s) form given key
118 * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
119 * @param key key name
120 * @return the value name(s) plus the value(s)
121 * @throws IllegalArgumentException if hkey not HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
122 * @throws IllegalAccessException if Java language access control is enforced and the underlying method is inaccessible
123 * @throws InvocationTargetException if the underlying method throws an exception
124 */
125 public static Map<String, String> readStringValues(int hkey, String key)
126 throws IllegalAccessException, InvocationTargetException {
127 if (hkey == HKEY_LOCAL_MACHINE) {
128 return readStringValues(systemRoot, hkey, key);
129 } else if (hkey == HKEY_CURRENT_USER) {
130 return readStringValues(userRoot, hkey, key);
131 } else {
132 throw new IllegalArgumentException("hkey=" + hkey);
133 }
134 }
135
136 /**
137 * Read the value name(s) from a given key
138 * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
139 * @param key key name
140 * @return the value name(s)
141 * @throws IllegalArgumentException if hkey not HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
142 * @throws IllegalAccessException if Java language access control is enforced and the underlying method is inaccessible
143 * @throws InvocationTargetException if the underlying method throws an exception
144 */
145 public static List<String> readStringSubKeys(int hkey, String key)
146 throws IllegalAccessException, InvocationTargetException {
147 if (hkey == HKEY_LOCAL_MACHINE) {
148 return readStringSubKeys(systemRoot, hkey, key);
149 } else if (hkey == HKEY_CURRENT_USER) {
150 return readStringSubKeys(userRoot, hkey, key);
151 } else {
152 throw new IllegalArgumentException("hkey=" + hkey);
153 }
154 }
155
156 // =====================
157
158 private static Number getNumber(Object array, int index) {
159 if (array instanceof int[]) {
160 return ((int[]) array)[index];
161 } else if (array instanceof long[]) {
162 return ((long[]) array)[index];
163 }
164 throw new IllegalArgumentException();
165 }
166
167 private static String readString(Preferences root, int hkey, String key, String value)
168 throws IllegalAccessException, InvocationTargetException {
169 if (regOpenKey == null || regQueryValueEx == null || regCloseKey == null) {
170 return null;
171 }
172 // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
173 Object handles = regOpenKey.invoke(root, hkey(hkey), toCstr(key), Integer.valueOf(KEY_READ));
174 if (getNumber(handles, 1).longValue() != REG_SUCCESS) {
175 return null;
176 }
177 byte[] valb = (byte[]) regQueryValueEx.invoke(root, getNumber(handles, 0), toCstr(value));
178 regCloseKey.invoke(root, getNumber(handles, 0));
179 return (valb != null ? new String(valb, StandardCharsets.UTF_8).trim() : null);
180 }
181
182 private static Map<String, String> readStringValues(Preferences root, int hkey, String key)
183 throws IllegalAccessException, InvocationTargetException {
184 if (regOpenKey == null || regQueryInfoKey == null || regEnumValue == null || regCloseKey == null) {
185 return Collections.emptyMap();
186 }
187 HashMap<String, String> results = new HashMap<>();
188 // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
189 Object handles = regOpenKey.invoke(root, hkey(hkey), toCstr(key), Integer.valueOf(KEY_READ));
190 if (getNumber(handles, 1).longValue() != REG_SUCCESS) {
191 return Collections.emptyMap();
192 }
193 // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
194 Object info = regQueryInfoKey.invoke(root, getNumber(handles, 0));
195
196 int count = getNumber(info, 0).intValue();
197 int maxlen = getNumber(info, 3).intValue();
198 for (int index = 0; index < count; index++) {
199 byte[] name = (byte[]) regEnumValue.invoke(root, getNumber(handles, 0), Integer.valueOf(index), Integer.valueOf(maxlen + 1));
200 String value = readString(hkey, key, new String(name, StandardCharsets.UTF_8));
201 results.put(new String(name, StandardCharsets.UTF_8).trim(), value);
202 }
203 regCloseKey.invoke(root, getNumber(handles, 0));
204 return results;
205 }
206
207 private static List<String> readStringSubKeys(Preferences root, int hkey, String key)
208 throws IllegalAccessException, InvocationTargetException {
209 if (regOpenKey == null || regQueryInfoKey == null || regEnumKeyEx == null || regCloseKey == null) {
210 return Collections.emptyList();
211 }
212 List<String> results = new ArrayList<>();
213 // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
214 Object handles = regOpenKey.invoke(root, hkey(hkey), toCstr(key), Integer.valueOf(KEY_READ));
215 if (getNumber(handles, 1).longValue() != REG_SUCCESS) {
216 return Collections.emptyList();
217 }
218 // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
219 Object info = regQueryInfoKey.invoke(root, getNumber(handles, 0));
220
221 int count = getNumber(info, 0).intValue();
222 int maxlen = getNumber(info, 3).intValue();
223 for (int index = 0; index < count; index++) {
224 byte[] name = (byte[]) regEnumKeyEx.invoke(root, getNumber(handles, 0), Integer.valueOf(index), Integer.valueOf(maxlen + 1));
225 results.add(new String(name, StandardCharsets.UTF_8).trim());
226 }
227 regCloseKey.invoke(root, getNumber(handles, 0));
228 return results;
229 }
230
231 // utility
232 private static byte[] toCstr(String str) {
233 byte[] array = str.getBytes(StandardCharsets.UTF_8);
234 byte[] biggerCopy = Arrays.copyOf(array, array.length + 1);
235 biggerCopy[array.length] = 0;
236 return biggerCopy;
237 }
238}
Note: See TracBrowser for help on using the repository browser.