Subject: [PATCH] 23725
---
Index: src/org/openstreetmap/josm/tools/WinRegistry.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/org/openstreetmap/josm/tools/WinRegistry.java b/src/org/openstreetmap/josm/tools/WinRegistry.java
--- a/src/org/openstreetmap/josm/tools/WinRegistry.java	(revision 19099)
+++ b/src/org/openstreetmap/josm/tools/WinRegistry.java	(date 1718054953666)
@@ -28,7 +28,7 @@
      * colors, printers, network connections, and application preferences.
      * See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724836(v=vs.85).aspx">Predefined Keys</a>
      */
-    public static final int HKEY_CURRENT_USER = 0x80000001;
+    public static final long HKEY_CURRENT_USER = 0x80000001L;
 
     /**
      * Registry entries subordinate to this key define the physical state of the computer, including data about the bus type,
@@ -38,44 +38,59 @@
      * names and the location of the server), and other system information.
      * See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724836(v=vs.85).aspx">Predefined Keys</a>
      */
-    public static final int HKEY_LOCAL_MACHINE = 0x80000002;
+    public static final long HKEY_LOCAL_MACHINE = 0x80000002L;
 
     private static final long REG_SUCCESS = 0L;
 
     private static final int KEY_READ = 0x20019;
-    private static final Preferences userRoot = Preferences.userRoot();
-    private static final Preferences systemRoot = Preferences.systemRoot();
-    private static final Class<? extends Preferences> userClass = userRoot.getClass();
-    private static final Method regOpenKey;
-    private static final Method regCloseKey;
-    private static final Method regQueryValueEx;
-    private static final Method regEnumValue;
-    private static final Method regQueryInfoKey;
-    private static final Method regEnumKeyEx;
-
-    private static boolean java11;
+    private static final Preferences USER_ROOT = Preferences.userRoot();
+    private static final Preferences SYSTEM_ROOT = Preferences.systemRoot();
+    private static final Class<? extends Preferences> USER_CLASS = USER_ROOT.getClass();
+    /**
+     * Wrapper for Windows registry API RegOpenKey(long, byte[], int)
+     * Returns {@code long[]}
+     */
+    private static final Method REG_OPEN_KEY;
+    /**
+     * Wrapper for Windows registry API RegCloseKey(long)
+     * Returns {@code int}
+     */
+    private static final Method REG_CLOSE_KEY;
+    /**
+     * Wrapper for Windows registry API RegQueryValueEx(long, byte[])
+     * Returns {@code byte[]}
+     */
+    private static final Method REG_QUERY_VALUE_EX;
+    /**
+     * Wrapper for Windows registry API RegEnumValue(long, int, int)
+     * Returns {@code byte[]}
+     */
+    private static final Method REG_ENUM_VALUE;
+    /**
+     * Wrapper for RegQueryInfoKey(long)
+     * Returns {@code long[]}
+     */
+    private static final Method REG_QUERY_INFO_KEY;
+    /**
+     * Wrapper for RegEnumKeyEx(long, int, int)
+     * Returns {@code byte[]}
+     */
+    private static final Method REG_ENUM_KEY_EX;
 
     static {
-        regOpenKey = getDeclaredMethod("WindowsRegOpenKey", int.class, byte[].class, int.class);
-        regCloseKey = getDeclaredMethod("WindowsRegCloseKey", int.class);
-        regQueryValueEx = getDeclaredMethod("WindowsRegQueryValueEx", int.class, byte[].class);
-        regEnumValue = getDeclaredMethod("WindowsRegEnumValue", int.class, int.class, int.class);
-        regQueryInfoKey = getDeclaredMethod("WindowsRegQueryInfoKey1", int.class);
-        regEnumKeyEx = getDeclaredMethod("WindowsRegEnumKeyEx", int.class, int.class, int.class);
-        ReflectionUtils.setObjectsAccessible(regOpenKey, regCloseKey, regQueryValueEx, regEnumValue, regQueryInfoKey, regEnumKeyEx);
+        REG_OPEN_KEY = getDeclaredMethod("WindowsRegOpenKey", long.class, byte[].class, int.class);
+        REG_CLOSE_KEY = getDeclaredMethod("WindowsRegCloseKey", long.class);
+        REG_QUERY_VALUE_EX = getDeclaredMethod("WindowsRegQueryValueEx", long.class, byte[].class);
+        REG_ENUM_VALUE = getDeclaredMethod("WindowsRegEnumValue", long.class, int.class, int.class);
+        REG_QUERY_INFO_KEY = getDeclaredMethod("WindowsRegQueryInfoKey1", long.class);
+        REG_ENUM_KEY_EX = getDeclaredMethod("WindowsRegEnumKeyEx", long.class, int.class, int.class);
+        ReflectionUtils.setObjectsAccessible(REG_OPEN_KEY, REG_CLOSE_KEY, REG_QUERY_VALUE_EX, REG_ENUM_VALUE, REG_QUERY_INFO_KEY, REG_ENUM_KEY_EX);
     }
 
     private static Method getDeclaredMethod(String name, Class<?>... parameterTypes) {
         try {
-            return userClass.getDeclaredMethod(name, parameterTypes);
+            return USER_CLASS.getDeclaredMethod(name, parameterTypes);
         } catch (NoSuchMethodException e) {
-            if (parameterTypes.length > 0 && parameterTypes[0] == int.class) {
-                // JDK-8198899: change of signature in Java 11. Old signature to drop when we switch to Java 11
-                Class<?>[] parameterTypesCopy = Utils.copyArray(parameterTypes);
-                parameterTypesCopy[0] = long.class;
-                java11 = true;
-                return getDeclaredMethod(name, parameterTypesCopy);
-            }
             Logging.log(Logging.LEVEL_ERROR, "Unable to find WindowsReg method", e);
             return null;
         } catch (RuntimeException e) {
@@ -84,10 +99,6 @@
         }
     }
 
-    private static Number hkey(int key) {
-        return java11 ? ((Number) Long.valueOf(key)) : ((Number) Integer.valueOf(key));
-    }
-
     private WinRegistry() {
         // Hide default constructor for utilities classes
     }
@@ -101,13 +112,14 @@
      * @throws IllegalArgumentException if hkey not HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
      * @throws IllegalAccessException if Java language access control is enforced and the underlying method is inaccessible
      * @throws InvocationTargetException if the underlying method throws an exception
+     * @since xxx (method definition)
      */
-    public static String readString(int hkey, String key, String valueName)
+    public static String readString(long hkey, String key, String valueName)
             throws IllegalAccessException, InvocationTargetException {
         if (hkey == HKEY_LOCAL_MACHINE) {
-            return readString(systemRoot, hkey, key, valueName);
+            return readString(SYSTEM_ROOT, hkey, key, valueName);
         } else if (hkey == HKEY_CURRENT_USER) {
-            return readString(userRoot, hkey, key, valueName);
+            return readString(USER_ROOT, hkey, key, valueName);
         } else {
             throw new IllegalArgumentException("hkey=" + hkey);
         }
@@ -122,12 +134,12 @@
      * @throws IllegalAccessException if Java language access control is enforced and the underlying method is inaccessible
      * @throws InvocationTargetException if the underlying method throws an exception
      */
-    public static Map<String, String> readStringValues(int hkey, String key)
+    public static Map<String, String> readStringValues(long hkey, String key)
             throws IllegalAccessException, InvocationTargetException {
         if (hkey == HKEY_LOCAL_MACHINE) {
-            return readStringValues(systemRoot, hkey, key);
+            return readStringValues(SYSTEM_ROOT, hkey, key);
         } else if (hkey == HKEY_CURRENT_USER) {
-            return readStringValues(userRoot, hkey, key);
+            return readStringValues(USER_ROOT, hkey, key);
         } else {
             throw new IllegalArgumentException("hkey=" + hkey);
         }
@@ -142,12 +154,12 @@
      * @throws IllegalAccessException if Java language access control is enforced and the underlying method is inaccessible
      * @throws InvocationTargetException if the underlying method throws an exception
      */
-    public static List<String> readStringSubKeys(int hkey, String key)
+    public static List<String> readStringSubKeys(long hkey, String key)
             throws IllegalAccessException, InvocationTargetException {
         if (hkey == HKEY_LOCAL_MACHINE) {
-            return readStringSubKeys(systemRoot, hkey, key);
+            return readStringSubKeys(SYSTEM_ROOT, hkey, key);
         } else if (hkey == HKEY_CURRENT_USER) {
-            return readStringSubKeys(userRoot, hkey, key);
+            return readStringSubKeys(USER_ROOT, hkey, key);
         } else {
             throw new IllegalArgumentException("hkey=" + hkey);
         }
@@ -155,76 +167,69 @@
 
     // =====================
 
-    private static Number getNumber(Object array, int index) {
-        if (array instanceof int[]) {
-            return ((int[]) array)[index];
-        } else if (array instanceof long[]) {
+    private static long getNumber(Object array, int index) {
+        if (array instanceof long[]) {
             return ((long[]) array)[index];
         }
         throw new IllegalArgumentException();
     }
 
-    private static String readString(Preferences root, int hkey, String key, String value)
+    private static String readString(Preferences root, long hkey, String key, String value)
             throws IllegalAccessException, InvocationTargetException {
-        if (regOpenKey == null || regQueryValueEx == null || regCloseKey == null) {
+        if (REG_OPEN_KEY == null || REG_QUERY_VALUE_EX == null || REG_CLOSE_KEY == null) {
             return null;
         }
-        // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
-        Object handles = regOpenKey.invoke(root, hkey(hkey), toCstr(key), Integer.valueOf(KEY_READ));
-        if (getNumber(handles, 1).longValue() != REG_SUCCESS) {
+        Object handles = REG_OPEN_KEY.invoke(root, hkey, toCstr(key), KEY_READ);
+        if (getNumber(handles, 1) != REG_SUCCESS) {
             return null;
         }
-        byte[] valb = (byte[]) regQueryValueEx.invoke(root, getNumber(handles, 0), toCstr(value));
-        regCloseKey.invoke(root, getNumber(handles, 0));
+        byte[] valb = (byte[]) REG_QUERY_VALUE_EX.invoke(root, getNumber(handles, 0), toCstr(value));
+        REG_CLOSE_KEY.invoke(root, getNumber(handles, 0));
         return (valb != null ? new String(valb, StandardCharsets.UTF_8).trim() : null);
     }
 
-    private static Map<String, String> readStringValues(Preferences root, int hkey, String key)
+    private static Map<String, String> readStringValues(Preferences root, long hkey, String key)
             throws IllegalAccessException, InvocationTargetException {
-        if (regOpenKey == null || regQueryInfoKey == null || regEnumValue == null || regCloseKey == null) {
+        if (REG_OPEN_KEY == null || REG_QUERY_INFO_KEY == null || REG_ENUM_VALUE == null || REG_CLOSE_KEY == null) {
             return Collections.emptyMap();
         }
         HashMap<String, String> results = new HashMap<>();
-        // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
-        Object handles = regOpenKey.invoke(root, hkey(hkey), toCstr(key), Integer.valueOf(KEY_READ));
-        if (getNumber(handles, 1).longValue() != REG_SUCCESS) {
+        Object handles = REG_OPEN_KEY.invoke(root, hkey, toCstr(key), KEY_READ);
+        if (getNumber(handles, 1) != REG_SUCCESS) {
             return Collections.emptyMap();
         }
-        // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
-        Object info = regQueryInfoKey.invoke(root, getNumber(handles, 0));
+        Object info = REG_QUERY_INFO_KEY.invoke(root, getNumber(handles, 0));
 
-        int count = getNumber(info, 0).intValue();
-        int maxlen = getNumber(info, 3).intValue();
+        int count = Math.toIntExact(getNumber(info, 0));
+        int maxlen = Math.toIntExact(getNumber(info, 3));
         for (int index = 0; index < count; index++) {
-            byte[] name = (byte[]) regEnumValue.invoke(root, getNumber(handles, 0), Integer.valueOf(index), Integer.valueOf(maxlen + 1));
+            byte[] name = (byte[]) REG_ENUM_VALUE.invoke(root, getNumber(handles, 0), index, maxlen + 1);
             String value = readString(hkey, key, new String(name, StandardCharsets.UTF_8));
             results.put(new String(name, StandardCharsets.UTF_8).trim(), value);
         }
-        regCloseKey.invoke(root, getNumber(handles, 0));
+        REG_CLOSE_KEY.invoke(root, getNumber(handles, 0));
         return Collections.unmodifiableMap(results);
     }
 
-    private static List<String> readStringSubKeys(Preferences root, int hkey, String key)
+    private static List<String> readStringSubKeys(Preferences root, long hkey, String key)
             throws IllegalAccessException, InvocationTargetException {
-        if (regOpenKey == null || regQueryInfoKey == null || regEnumKeyEx == null || regCloseKey == null) {
+        if (REG_OPEN_KEY == null || REG_QUERY_INFO_KEY == null || REG_ENUM_KEY_EX == null || REG_CLOSE_KEY == null) {
             return Collections.emptyList();
         }
         List<String> results = new ArrayList<>();
-        // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
-        Object handles = regOpenKey.invoke(root, hkey(hkey), toCstr(key), Integer.valueOf(KEY_READ));
-        if (getNumber(handles, 1).longValue() != REG_SUCCESS) {
+        Object handles = REG_OPEN_KEY.invoke(root, hkey, toCstr(key), KEY_READ);
+        if (getNumber(handles, 1) != REG_SUCCESS) {
             return Collections.emptyList();
         }
-        // Need to capture both int[] (Java 8-10) and long[] (Java 11+)
-        Object info = regQueryInfoKey.invoke(root, getNumber(handles, 0));
+        Object info = REG_QUERY_INFO_KEY.invoke(root, getNumber(handles, 0));
 
-        int count = getNumber(info, 0).intValue();
-        int maxlen = getNumber(info, 3).intValue();
+        int count = Math.toIntExact(getNumber(info, 0));
+        int maxlen = Math.toIntExact(getNumber(info, 3));
         for (int index = 0; index < count; index++) {
-            byte[] name = (byte[]) regEnumKeyEx.invoke(root, getNumber(handles, 0), Integer.valueOf(index), Integer.valueOf(maxlen + 1));
+            byte[] name = (byte[]) REG_ENUM_KEY_EX.invoke(root, getNumber(handles, 0), index, maxlen + 1);
             results.add(new String(name, StandardCharsets.UTF_8).trim());
         }
-        regCloseKey.invoke(root, getNumber(handles, 0));
+        REG_CLOSE_KEY.invoke(root, getNumber(handles, 0));
         return Collections.unmodifiableList(results);
     }
 
