Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/java/util/prefs/WindowsPreferences.java
32288 views
1
/*
2
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package java.util.prefs;
27
28
import java.util.Map;
29
import java.util.TreeMap;
30
import java.util.StringTokenizer;
31
import java.io.ByteArrayOutputStream;
32
import sun.util.logging.PlatformLogger;
33
34
/**
35
* Windows registry based implementation of <tt>Preferences</tt>.
36
* <tt>Preferences</tt>' <tt>systemRoot</tt> and <tt>userRoot</tt> are stored in
37
* <tt>HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs</tt> and
38
* <tt>HKEY_CURRENT_USER\Software\JavaSoft\Prefs</tt> correspondingly.
39
*
40
* @author Konstantin Kladko
41
* @see Preferences
42
* @see PreferencesFactory
43
* @since 1.4
44
*/
45
46
class WindowsPreferences extends AbstractPreferences{
47
48
/**
49
* Logger for error messages
50
*/
51
private static PlatformLogger logger;
52
53
/**
54
* Windows registry path to <tt>Preferences</tt>'s root nodes.
55
*/
56
private static final byte[] WINDOWS_ROOT_PATH =
57
stringToByteArray("Software\\JavaSoft\\Prefs");
58
59
/**
60
* Windows handles to <tt>HKEY_CURRENT_USER</tt> and
61
* <tt>HKEY_LOCAL_MACHINE</tt> hives.
62
*/
63
private static final int HKEY_CURRENT_USER = 0x80000001;
64
private static final int HKEY_LOCAL_MACHINE = 0x80000002;
65
66
/**
67
* Mount point for <tt>Preferences</tt>' user root.
68
*/
69
private static final int USER_ROOT_NATIVE_HANDLE = HKEY_CURRENT_USER;
70
71
/**
72
* Mount point for <tt>Preferences</tt>' system root.
73
*/
74
private static final int SYSTEM_ROOT_NATIVE_HANDLE = HKEY_LOCAL_MACHINE;
75
76
/**
77
* Maximum byte-encoded path length for Windows native functions,
78
* ending <tt>null</tt> character not included.
79
*/
80
private static final int MAX_WINDOWS_PATH_LENGTH = 256;
81
82
/**
83
* User root node.
84
*/
85
private static volatile Preferences userRoot;
86
87
static Preferences getUserRoot() {
88
Preferences root = userRoot;
89
if (root == null) {
90
synchronized (WindowsPreferences.class) {
91
root = userRoot;
92
if (root == null) {
93
root = new WindowsPreferences(USER_ROOT_NATIVE_HANDLE, WINDOWS_ROOT_PATH);
94
userRoot = root;
95
}
96
}
97
}
98
return root;
99
}
100
101
/**
102
* System root node.
103
*/
104
private static volatile Preferences systemRoot;
105
106
static Preferences getSystemRoot() {
107
Preferences root = systemRoot;
108
if (root == null) {
109
synchronized (WindowsPreferences.class) {
110
root = systemRoot;
111
if (root == null) {
112
root = new WindowsPreferences(SYSTEM_ROOT_NATIVE_HANDLE, WINDOWS_ROOT_PATH);
113
systemRoot = root;
114
}
115
}
116
}
117
return root;
118
}
119
120
/* Windows error codes. */
121
private static final int ERROR_SUCCESS = 0;
122
private static final int ERROR_FILE_NOT_FOUND = 2;
123
private static final int ERROR_ACCESS_DENIED = 5;
124
125
/* Constants used to interpret returns of native functions */
126
private static final int NATIVE_HANDLE = 0;
127
private static final int ERROR_CODE = 1;
128
private static final int SUBKEYS_NUMBER = 0;
129
private static final int VALUES_NUMBER = 2;
130
private static final int MAX_KEY_LENGTH = 3;
131
private static final int MAX_VALUE_NAME_LENGTH = 4;
132
private static final int DISPOSITION = 2;
133
private static final int REG_CREATED_NEW_KEY = 1;
134
private static final int REG_OPENED_EXISTING_KEY = 2;
135
private static final int NULL_NATIVE_HANDLE = 0;
136
137
/* Windows security masks */
138
private static final int DELETE = 0x10000;
139
private static final int KEY_QUERY_VALUE = 1;
140
private static final int KEY_SET_VALUE = 2;
141
private static final int KEY_CREATE_SUB_KEY = 4;
142
private static final int KEY_ENUMERATE_SUB_KEYS = 8;
143
private static final int KEY_READ = 0x20019;
144
private static final int KEY_WRITE = 0x20006;
145
private static final int KEY_ALL_ACCESS = 0xf003f;
146
147
/**
148
* Initial time between registry access attempts, in ms. The time is doubled
149
* after each failing attempt (except the first).
150
*/
151
private static int INIT_SLEEP_TIME = 50;
152
153
/**
154
* Maximum number of registry access attempts.
155
*/
156
private static int MAX_ATTEMPTS = 5;
157
158
/**
159
* BackingStore availability flag.
160
*/
161
private boolean isBackingStoreAvailable = true;
162
163
/**
164
* Java wrapper for Windows registry API RegOpenKey()
165
*/
166
private static native int[] WindowsRegOpenKey(int hKey, byte[] subKey,
167
int securityMask);
168
/**
169
* Retries RegOpenKey() MAX_ATTEMPTS times before giving up.
170
*/
171
private static int[] WindowsRegOpenKey1(int hKey, byte[] subKey,
172
int securityMask) {
173
int[] result = WindowsRegOpenKey(hKey, subKey, securityMask);
174
if (result[ERROR_CODE] == ERROR_SUCCESS) {
175
return result;
176
} else if (result[ERROR_CODE] == ERROR_FILE_NOT_FOUND) {
177
logger().warning("Trying to recreate Windows registry node " +
178
byteArrayToString(subKey) + " at root 0x" +
179
Integer.toHexString(hKey) + ".");
180
// Try recreation
181
int handle = WindowsRegCreateKeyEx(hKey, subKey)[NATIVE_HANDLE];
182
WindowsRegCloseKey(handle);
183
return WindowsRegOpenKey(hKey, subKey, securityMask);
184
} else if (result[ERROR_CODE] != ERROR_ACCESS_DENIED) {
185
long sleepTime = INIT_SLEEP_TIME;
186
for (int i = 0; i < MAX_ATTEMPTS; i++) {
187
try {
188
Thread.sleep(sleepTime);
189
} catch(InterruptedException e) {
190
return result;
191
}
192
sleepTime *= 2;
193
result = WindowsRegOpenKey(hKey, subKey, securityMask);
194
if (result[ERROR_CODE] == ERROR_SUCCESS) {
195
return result;
196
}
197
}
198
}
199
return result;
200
}
201
202
/**
203
* Java wrapper for Windows registry API RegCloseKey()
204
*/
205
private static native int WindowsRegCloseKey(int hKey);
206
207
/**
208
* Java wrapper for Windows registry API RegCreateKeyEx()
209
*/
210
private static native int[] WindowsRegCreateKeyEx(int hKey, byte[] subKey);
211
212
/**
213
* Retries RegCreateKeyEx() MAX_ATTEMPTS times before giving up.
214
*/
215
private static int[] WindowsRegCreateKeyEx1(int hKey, byte[] subKey) {
216
int[] result = WindowsRegCreateKeyEx(hKey, subKey);
217
if (result[ERROR_CODE] == ERROR_SUCCESS) {
218
return result;
219
} else {
220
long sleepTime = INIT_SLEEP_TIME;
221
for (int i = 0; i < MAX_ATTEMPTS; i++) {
222
try {
223
Thread.sleep(sleepTime);
224
} catch(InterruptedException e) {
225
return result;
226
}
227
sleepTime *= 2;
228
result = WindowsRegCreateKeyEx(hKey, subKey);
229
if (result[ERROR_CODE] == ERROR_SUCCESS) {
230
return result;
231
}
232
}
233
}
234
return result;
235
}
236
/**
237
* Java wrapper for Windows registry API RegDeleteKey()
238
*/
239
private static native int WindowsRegDeleteKey(int hKey, byte[] subKey);
240
241
/**
242
* Java wrapper for Windows registry API RegFlushKey()
243
*/
244
private static native int WindowsRegFlushKey(int hKey);
245
246
/**
247
* Retries RegFlushKey() MAX_ATTEMPTS times before giving up.
248
*/
249
private static int WindowsRegFlushKey1(int hKey) {
250
int result = WindowsRegFlushKey(hKey);
251
if (result == ERROR_SUCCESS) {
252
return result;
253
} else {
254
long sleepTime = INIT_SLEEP_TIME;
255
for (int i = 0; i < MAX_ATTEMPTS; i++) {
256
try {
257
Thread.sleep(sleepTime);
258
} catch(InterruptedException e) {
259
return result;
260
}
261
sleepTime *= 2;
262
result = WindowsRegFlushKey(hKey);
263
if (result == ERROR_SUCCESS) {
264
return result;
265
}
266
}
267
}
268
return result;
269
}
270
271
/**
272
* Java wrapper for Windows registry API RegQueryValueEx()
273
*/
274
private static native byte[] WindowsRegQueryValueEx(int hKey,
275
byte[] valueName);
276
/**
277
* Java wrapper for Windows registry API RegSetValueEx()
278
*/
279
private static native int WindowsRegSetValueEx(int hKey, byte[] valueName,
280
byte[] value);
281
/**
282
* Retries RegSetValueEx() MAX_ATTEMPTS times before giving up.
283
*/
284
private static int WindowsRegSetValueEx1(int hKey, byte[] valueName,
285
byte[] value) {
286
int result = WindowsRegSetValueEx(hKey, valueName, value);
287
if (result == ERROR_SUCCESS) {
288
return result;
289
} else {
290
long sleepTime = INIT_SLEEP_TIME;
291
for (int i = 0; i < MAX_ATTEMPTS; i++) {
292
try {
293
Thread.sleep(sleepTime);
294
} catch(InterruptedException e) {
295
return result;
296
}
297
sleepTime *= 2;
298
result = WindowsRegSetValueEx(hKey, valueName, value);
299
if (result == ERROR_SUCCESS) {
300
return result;
301
}
302
}
303
}
304
return result;
305
}
306
307
/**
308
* Java wrapper for Windows registry API RegDeleteValue()
309
*/
310
private static native int WindowsRegDeleteValue(int hKey, byte[] valueName);
311
312
/**
313
* Java wrapper for Windows registry API RegQueryInfoKey()
314
*/
315
private static native int[] WindowsRegQueryInfoKey(int hKey);
316
317
/**
318
* Retries RegQueryInfoKey() MAX_ATTEMPTS times before giving up.
319
*/
320
private static int[] WindowsRegQueryInfoKey1(int hKey) {
321
int[] result = WindowsRegQueryInfoKey(hKey);
322
if (result[ERROR_CODE] == ERROR_SUCCESS) {
323
return result;
324
} else {
325
long sleepTime = INIT_SLEEP_TIME;
326
for (int i = 0; i < MAX_ATTEMPTS; i++) {
327
try {
328
Thread.sleep(sleepTime);
329
} catch(InterruptedException e) {
330
return result;
331
}
332
sleepTime *= 2;
333
result = WindowsRegQueryInfoKey(hKey);
334
if (result[ERROR_CODE] == ERROR_SUCCESS) {
335
return result;
336
}
337
}
338
}
339
return result;
340
}
341
342
/**
343
* Java wrapper for Windows registry API RegEnumKeyEx()
344
*/
345
private static native byte[] WindowsRegEnumKeyEx(int hKey, int subKeyIndex,
346
int maxKeyLength);
347
348
/**
349
* Retries RegEnumKeyEx() MAX_ATTEMPTS times before giving up.
350
*/
351
private static byte[] WindowsRegEnumKeyEx1(int hKey, int subKeyIndex,
352
int maxKeyLength) {
353
byte[] result = WindowsRegEnumKeyEx(hKey, subKeyIndex, maxKeyLength);
354
if (result != null) {
355
return result;
356
} else {
357
long sleepTime = INIT_SLEEP_TIME;
358
for (int i = 0; i < MAX_ATTEMPTS; i++) {
359
try {
360
Thread.sleep(sleepTime);
361
} catch(InterruptedException e) {
362
return result;
363
}
364
sleepTime *= 2;
365
result = WindowsRegEnumKeyEx(hKey, subKeyIndex, maxKeyLength);
366
if (result != null) {
367
return result;
368
}
369
}
370
}
371
return result;
372
}
373
374
/**
375
* Java wrapper for Windows registry API RegEnumValue()
376
*/
377
private static native byte[] WindowsRegEnumValue(int hKey, int valueIndex,
378
int maxValueNameLength);
379
/**
380
* Retries RegEnumValueEx() MAX_ATTEMPTS times before giving up.
381
*/
382
private static byte[] WindowsRegEnumValue1(int hKey, int valueIndex,
383
int maxValueNameLength) {
384
byte[] result = WindowsRegEnumValue(hKey, valueIndex,
385
maxValueNameLength);
386
if (result != null) {
387
return result;
388
} else {
389
long sleepTime = INIT_SLEEP_TIME;
390
for (int i = 0; i < MAX_ATTEMPTS; i++) {
391
try {
392
Thread.sleep(sleepTime);
393
} catch(InterruptedException e) {
394
return result;
395
}
396
sleepTime *= 2;
397
result = WindowsRegEnumValue(hKey, valueIndex,
398
maxValueNameLength);
399
if (result != null) {
400
return result;
401
}
402
}
403
}
404
return result;
405
}
406
407
/**
408
* Constructs a <tt>WindowsPreferences</tt> node, creating underlying
409
* Windows registry node and all its Windows parents, if they are not yet
410
* created.
411
* Logs a warning message, if Windows Registry is unavailable.
412
*/
413
private WindowsPreferences(WindowsPreferences parent, String name) {
414
super(parent, name);
415
int parentNativeHandle = parent.openKey(KEY_CREATE_SUB_KEY, KEY_READ);
416
if (parentNativeHandle == NULL_NATIVE_HANDLE) {
417
// if here, openKey failed and logged
418
isBackingStoreAvailable = false;
419
return;
420
}
421
int[] result =
422
WindowsRegCreateKeyEx1(parentNativeHandle, toWindowsName(name));
423
if (result[ERROR_CODE] != ERROR_SUCCESS) {
424
logger().warning("Could not create windows registry node " +
425
byteArrayToString(windowsAbsolutePath()) +
426
" at root 0x" + Integer.toHexString(rootNativeHandle()) +
427
". Windows RegCreateKeyEx(...) returned error code " +
428
result[ERROR_CODE] + ".");
429
isBackingStoreAvailable = false;
430
return;
431
}
432
newNode = (result[DISPOSITION] == REG_CREATED_NEW_KEY);
433
closeKey(parentNativeHandle);
434
closeKey(result[NATIVE_HANDLE]);
435
}
436
437
/**
438
* Constructs a root node creating the underlying
439
* Windows registry node and all of its parents, if they have not yet been
440
* created.
441
* Logs a warning message, if Windows Registry is unavailable.
442
* @param rootNativeHandle Native handle to one of Windows top level keys.
443
* @param rootDirectory Path to root directory, as a byte-encoded string.
444
*/
445
private WindowsPreferences(int rootNativeHandle, byte[] rootDirectory) {
446
super(null, "");
447
int[] result =
448
WindowsRegCreateKeyEx1(rootNativeHandle, rootDirectory);
449
if (result[ERROR_CODE] != ERROR_SUCCESS) {
450
logger().warning("Could not open/create prefs root node " +
451
byteArrayToString(windowsAbsolutePath()) +
452
" at root 0x" + Integer.toHexString(rootNativeHandle()) +
453
". Windows RegCreateKeyEx(...) returned error code " +
454
result[ERROR_CODE] + ".");
455
isBackingStoreAvailable = false;
456
return;
457
}
458
// Check if a new node
459
newNode = (result[DISPOSITION] == REG_CREATED_NEW_KEY);
460
closeKey(result[NATIVE_HANDLE]);
461
}
462
463
/**
464
* Returns Windows absolute path of the current node as a byte array.
465
* Java "/" separator is transformed into Windows "\".
466
* @see Preferences#absolutePath()
467
*/
468
private byte[] windowsAbsolutePath() {
469
ByteArrayOutputStream bstream = new ByteArrayOutputStream();
470
bstream.write(WINDOWS_ROOT_PATH, 0, WINDOWS_ROOT_PATH.length-1);
471
StringTokenizer tokenizer = new StringTokenizer(absolutePath(), "/");
472
while (tokenizer.hasMoreTokens()) {
473
bstream.write((byte)'\\');
474
String nextName = tokenizer.nextToken();
475
byte[] windowsNextName = toWindowsName(nextName);
476
bstream.write(windowsNextName, 0, windowsNextName.length-1);
477
}
478
bstream.write(0);
479
return bstream.toByteArray();
480
}
481
482
/**
483
* Opens current node's underlying Windows registry key using a
484
* given security mask.
485
* @param securityMask Windows security mask.
486
* @return Windows registry key's handle.
487
* @see #openKey(byte[], int)
488
* @see #openKey(int, byte[], int)
489
* @see #closeKey(int)
490
*/
491
private int openKey(int securityMask) {
492
return openKey(securityMask, securityMask);
493
}
494
495
/**
496
* Opens current node's underlying Windows registry key using a
497
* given security mask.
498
* @param mask1 Preferred Windows security mask.
499
* @param mask2 Alternate Windows security mask.
500
* @return Windows registry key's handle.
501
* @see #openKey(byte[], int)
502
* @see #openKey(int, byte[], int)
503
* @see #closeKey(int)
504
*/
505
private int openKey(int mask1, int mask2) {
506
return openKey(windowsAbsolutePath(), mask1, mask2);
507
}
508
509
/**
510
* Opens Windows registry key at a given absolute path using a given
511
* security mask.
512
* @param windowsAbsolutePath Windows absolute path of the
513
* key as a byte-encoded string.
514
* @param mask1 Preferred Windows security mask.
515
* @param mask2 Alternate Windows security mask.
516
* @return Windows registry key's handle.
517
* @see #openKey(int)
518
* @see #openKey(int, byte[],int)
519
* @see #closeKey(int)
520
*/
521
private int openKey(byte[] windowsAbsolutePath, int mask1, int mask2) {
522
/* Check if key's path is short enough be opened at once
523
otherwise use a path-splitting procedure */
524
if (windowsAbsolutePath.length <= MAX_WINDOWS_PATH_LENGTH + 1) {
525
int[] result = WindowsRegOpenKey1(rootNativeHandle(),
526
windowsAbsolutePath, mask1);
527
if (result[ERROR_CODE] == ERROR_ACCESS_DENIED && mask2 != mask1)
528
result = WindowsRegOpenKey1(rootNativeHandle(),
529
windowsAbsolutePath, mask2);
530
531
if (result[ERROR_CODE] != ERROR_SUCCESS) {
532
logger().warning("Could not open windows registry node " +
533
byteArrayToString(windowsAbsolutePath()) +
534
" at root 0x" +
535
Integer.toHexString(rootNativeHandle()) +
536
". Windows RegOpenKey(...) returned error code " +
537
result[ERROR_CODE] + ".");
538
result[NATIVE_HANDLE] = NULL_NATIVE_HANDLE;
539
if (result[ERROR_CODE] == ERROR_ACCESS_DENIED) {
540
throw new SecurityException(
541
"Could not open windows registry node " +
542
byteArrayToString(windowsAbsolutePath()) +
543
" at root 0x" +
544
Integer.toHexString(rootNativeHandle()) +
545
": Access denied");
546
}
547
}
548
return result[NATIVE_HANDLE];
549
} else {
550
return openKey(rootNativeHandle(), windowsAbsolutePath, mask1, mask2);
551
}
552
}
553
554
/**
555
* Opens Windows registry key at a given relative path
556
* with respect to a given Windows registry key.
557
* @param windowsAbsolutePath Windows relative path of the
558
* key as a byte-encoded string.
559
* @param nativeHandle handle to the base Windows key.
560
* @param mask1 Preferred Windows security mask.
561
* @param mask2 Alternate Windows security mask.
562
* @return Windows registry key's handle.
563
* @see #openKey(int)
564
* @see #openKey(byte[],int)
565
* @see #closeKey(int)
566
*/
567
private int openKey(int nativeHandle, byte[] windowsRelativePath,
568
int mask1, int mask2) {
569
/* If the path is short enough open at once. Otherwise split the path */
570
if (windowsRelativePath.length <= MAX_WINDOWS_PATH_LENGTH + 1 ) {
571
int[] result = WindowsRegOpenKey1(nativeHandle,
572
windowsRelativePath, mask1);
573
if (result[ERROR_CODE] == ERROR_ACCESS_DENIED && mask2 != mask1)
574
result = WindowsRegOpenKey1(nativeHandle,
575
windowsRelativePath, mask2);
576
577
if (result[ERROR_CODE] != ERROR_SUCCESS) {
578
logger().warning("Could not open windows registry node " +
579
byteArrayToString(windowsAbsolutePath()) +
580
" at root 0x" + Integer.toHexString(nativeHandle) +
581
". Windows RegOpenKey(...) returned error code " +
582
result[ERROR_CODE] + ".");
583
result[NATIVE_HANDLE] = NULL_NATIVE_HANDLE;
584
}
585
return result[NATIVE_HANDLE];
586
} else {
587
int separatorPosition = -1;
588
// Be greedy - open the longest possible path
589
for (int i = MAX_WINDOWS_PATH_LENGTH; i > 0; i--) {
590
if (windowsRelativePath[i] == ((byte)'\\')) {
591
separatorPosition = i;
592
break;
593
}
594
}
595
// Split the path and do the recursion
596
byte[] nextRelativeRoot = new byte[separatorPosition+1];
597
System.arraycopy(windowsRelativePath, 0, nextRelativeRoot,0,
598
separatorPosition);
599
nextRelativeRoot[separatorPosition] = 0;
600
byte[] nextRelativePath = new byte[windowsRelativePath.length -
601
separatorPosition - 1];
602
System.arraycopy(windowsRelativePath, separatorPosition+1,
603
nextRelativePath, 0, nextRelativePath.length);
604
int nextNativeHandle = openKey(nativeHandle, nextRelativeRoot,
605
mask1, mask2);
606
if (nextNativeHandle == NULL_NATIVE_HANDLE) {
607
return NULL_NATIVE_HANDLE;
608
}
609
int result = openKey(nextNativeHandle, nextRelativePath,
610
mask1,mask2);
611
closeKey(nextNativeHandle);
612
return result;
613
}
614
}
615
616
/**
617
* Closes Windows registry key.
618
* Logs a warning if Windows registry is unavailable.
619
* @param key's Windows registry handle.
620
* @see #openKey(int)
621
* @see #openKey(byte[],int)
622
* @see #openKey(int, byte[],int)
623
*/
624
private void closeKey(int nativeHandle) {
625
int result = WindowsRegCloseKey(nativeHandle);
626
if (result != ERROR_SUCCESS) {
627
logger().warning("Could not close windows registry node " +
628
byteArrayToString(windowsAbsolutePath()) +
629
" at root 0x" +
630
Integer.toHexString(rootNativeHandle()) +
631
". Windows RegCloseKey(...) returned error code " +
632
result + ".");
633
}
634
}
635
636
/**
637
* Implements <tt>AbstractPreferences</tt> <tt>putSpi()</tt> method.
638
* Puts name-value pair into the underlying Windows registry node.
639
* Logs a warning, if Windows registry is unavailable.
640
* @see #getSpi(String)
641
*/
642
protected void putSpi(String javaName, String value) {
643
int nativeHandle = openKey(KEY_SET_VALUE);
644
if (nativeHandle == NULL_NATIVE_HANDLE) {
645
isBackingStoreAvailable = false;
646
return;
647
}
648
int result = WindowsRegSetValueEx1(nativeHandle,
649
toWindowsName(javaName), toWindowsValueString(value));
650
if (result != ERROR_SUCCESS) {
651
logger().warning("Could not assign value to key " +
652
byteArrayToString(toWindowsName(javaName)) +
653
" at Windows registry node " +
654
byteArrayToString(windowsAbsolutePath()) +
655
" at root 0x" +
656
Integer.toHexString(rootNativeHandle()) +
657
". Windows RegSetValueEx(...) returned error code " +
658
result + ".");
659
isBackingStoreAvailable = false;
660
}
661
closeKey(nativeHandle);
662
}
663
664
/**
665
* Implements <tt>AbstractPreferences</tt> <tt>getSpi()</tt> method.
666
* Gets a string value from the underlying Windows registry node.
667
* Logs a warning, if Windows registry is unavailable.
668
* @see #putSpi(String, String)
669
*/
670
protected String getSpi(String javaName) {
671
int nativeHandle = openKey(KEY_QUERY_VALUE);
672
if (nativeHandle == NULL_NATIVE_HANDLE) {
673
return null;
674
}
675
Object resultObject = WindowsRegQueryValueEx(nativeHandle,
676
toWindowsName(javaName));
677
if (resultObject == null) {
678
closeKey(nativeHandle);
679
return null;
680
}
681
closeKey(nativeHandle);
682
return toJavaValueString((byte[]) resultObject);
683
}
684
685
/**
686
* Implements <tt>AbstractPreferences</tt> <tt>removeSpi()</tt> method.
687
* Deletes a string name-value pair from the underlying Windows registry
688
* node, if this value still exists.
689
* Logs a warning, if Windows registry is unavailable or key has already
690
* been deleted.
691
*/
692
protected void removeSpi(String key) {
693
int nativeHandle = openKey(KEY_SET_VALUE);
694
if (nativeHandle == NULL_NATIVE_HANDLE) {
695
return;
696
}
697
int result =
698
WindowsRegDeleteValue(nativeHandle, toWindowsName(key));
699
if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
700
logger().warning("Could not delete windows registry value " +
701
byteArrayToString(windowsAbsolutePath()) + "\\" +
702
toWindowsName(key) + " at root 0x" +
703
Integer.toHexString(rootNativeHandle()) +
704
". Windows RegDeleteValue(...) returned error code " +
705
result + ".");
706
isBackingStoreAvailable = false;
707
}
708
closeKey(nativeHandle);
709
}
710
711
/**
712
* Implements <tt>AbstractPreferences</tt> <tt>keysSpi()</tt> method.
713
* Gets value names from the underlying Windows registry node.
714
* Throws a BackingStoreException and logs a warning, if
715
* Windows registry is unavailable.
716
*/
717
protected String[] keysSpi() throws BackingStoreException{
718
// Find out the number of values
719
int nativeHandle = openKey(KEY_QUERY_VALUE);
720
if (nativeHandle == NULL_NATIVE_HANDLE) {
721
throw new BackingStoreException(
722
"Could not open windows registry node " +
723
byteArrayToString(windowsAbsolutePath()) +
724
" at root 0x" +
725
Integer.toHexString(rootNativeHandle()) + ".");
726
}
727
int[] result = WindowsRegQueryInfoKey1(nativeHandle);
728
if (result[ERROR_CODE] != ERROR_SUCCESS) {
729
String info = "Could not query windows registry node " +
730
byteArrayToString(windowsAbsolutePath()) +
731
" at root 0x" +
732
Integer.toHexString(rootNativeHandle()) +
733
". Windows RegQueryInfoKeyEx(...) returned error code " +
734
result[ERROR_CODE] + ".";
735
logger().warning(info);
736
throw new BackingStoreException(info);
737
}
738
int maxValueNameLength = result[MAX_VALUE_NAME_LENGTH];
739
int valuesNumber = result[VALUES_NUMBER];
740
if (valuesNumber == 0) {
741
closeKey(nativeHandle);
742
return new String[0];
743
}
744
// Get the values
745
String[] valueNames = new String[valuesNumber];
746
for (int i = 0; i < valuesNumber; i++) {
747
byte[] windowsName = WindowsRegEnumValue1(nativeHandle, i,
748
maxValueNameLength+1);
749
if (windowsName == null) {
750
String info =
751
"Could not enumerate value #" + i + " of windows node " +
752
byteArrayToString(windowsAbsolutePath()) + " at root 0x" +
753
Integer.toHexString(rootNativeHandle()) + ".";
754
logger().warning(info);
755
throw new BackingStoreException(info);
756
}
757
valueNames[i] = toJavaName(windowsName);
758
}
759
closeKey(nativeHandle);
760
return valueNames;
761
}
762
763
/**
764
* Implements <tt>AbstractPreferences</tt> <tt>childrenNamesSpi()</tt> method.
765
* Calls Windows registry to retrive children of this node.
766
* Throws a BackingStoreException and logs a warning message,
767
* if Windows registry is not available.
768
*/
769
protected String[] childrenNamesSpi() throws BackingStoreException {
770
// Open key
771
int nativeHandle = openKey(KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE);
772
if (nativeHandle == NULL_NATIVE_HANDLE) {
773
throw new BackingStoreException(
774
"Could not open windows registry node " +
775
byteArrayToString(windowsAbsolutePath()) +
776
" at root 0x" +
777
Integer.toHexString(rootNativeHandle()) + ".");
778
}
779
// Get number of children
780
int[] result = WindowsRegQueryInfoKey1(nativeHandle);
781
if (result[ERROR_CODE] != ERROR_SUCCESS) {
782
String info = "Could not query windows registry node " +
783
byteArrayToString(windowsAbsolutePath()) +
784
" at root 0x" + Integer.toHexString(rootNativeHandle()) +
785
". Windows RegQueryInfoKeyEx(...) returned error code " +
786
result[ERROR_CODE] + ".";
787
logger().warning(info);
788
throw new BackingStoreException(info);
789
}
790
int maxKeyLength = result[MAX_KEY_LENGTH];
791
int subKeysNumber = result[SUBKEYS_NUMBER];
792
if (subKeysNumber == 0) {
793
closeKey(nativeHandle);
794
return new String[0];
795
}
796
String[] subkeys = new String[subKeysNumber];
797
String[] children = new String[subKeysNumber];
798
// Get children
799
for (int i = 0; i < subKeysNumber; i++) {
800
byte[] windowsName = WindowsRegEnumKeyEx1(nativeHandle, i,
801
maxKeyLength+1);
802
if (windowsName == null) {
803
String info =
804
"Could not enumerate key #" + i + " of windows node " +
805
byteArrayToString(windowsAbsolutePath()) + " at root 0x" +
806
Integer.toHexString(rootNativeHandle()) + ". ";
807
logger().warning(info);
808
throw new BackingStoreException(info);
809
}
810
String javaName = toJavaName(windowsName);
811
children[i] = javaName;
812
}
813
closeKey(nativeHandle);
814
return children;
815
}
816
817
/**
818
* Implements <tt>Preferences</tt> <tt>flush()</tt> method.
819
* Flushes Windows registry changes to disk.
820
* Throws a BackingStoreException and logs a warning message if Windows
821
* registry is not available.
822
*/
823
public void flush() throws BackingStoreException{
824
825
if (isRemoved()) {
826
parent.flush();
827
return;
828
}
829
if (!isBackingStoreAvailable) {
830
throw new BackingStoreException(
831
"flush(): Backing store not available.");
832
}
833
int nativeHandle = openKey(KEY_READ);
834
if (nativeHandle == NULL_NATIVE_HANDLE) {
835
throw new BackingStoreException(
836
"Could not open windows registry node " +
837
byteArrayToString(windowsAbsolutePath()) +
838
" at root 0x" +
839
Integer.toHexString(rootNativeHandle()) + ".");
840
}
841
int result = WindowsRegFlushKey1(nativeHandle);
842
if (result != ERROR_SUCCESS) {
843
String info = "Could not flush windows registry node " +
844
byteArrayToString(windowsAbsolutePath()) +
845
" at root 0x" +
846
Integer.toHexString(rootNativeHandle()) +
847
". Windows RegFlushKey(...) returned error code " +
848
result + ".";
849
logger().warning(info);
850
throw new BackingStoreException(info);
851
}
852
closeKey(nativeHandle);
853
}
854
855
856
/**
857
* Implements <tt>Preferences</tt> <tt>sync()</tt> method.
858
* Flushes Windows registry changes to disk. Equivalent to flush().
859
* @see flush()
860
*/
861
public void sync() throws BackingStoreException{
862
if (isRemoved())
863
throw new IllegalStateException("Node has been removed");
864
flush();
865
}
866
867
/**
868
* Implements <tt>AbstractPreferences</tt> <tt>childSpi()</tt> method.
869
* Constructs a child node with a
870
* given name and creates its underlying Windows registry node,
871
* if it does not exist.
872
* Logs a warning message, if Windows Registry is unavailable.
873
*/
874
protected AbstractPreferences childSpi(String name) {
875
return new WindowsPreferences(this, name);
876
}
877
878
/**
879
* Implements <tt>AbstractPreferences</tt> <tt>removeNodeSpi()</tt> method.
880
* Deletes underlying Windows registry node.
881
* Throws a BackingStoreException and logs a warning, if Windows registry
882
* is not available.
883
*/
884
public void removeNodeSpi() throws BackingStoreException {
885
int parentNativeHandle =
886
((WindowsPreferences)parent()).openKey(DELETE);
887
if (parentNativeHandle == NULL_NATIVE_HANDLE) {
888
throw new BackingStoreException(
889
"Could not open parent windows registry node of " +
890
byteArrayToString(windowsAbsolutePath()) +
891
" at root 0x" +
892
Integer.toHexString(rootNativeHandle()) + ".");
893
}
894
int result =
895
WindowsRegDeleteKey(parentNativeHandle, toWindowsName(name()));
896
if (result != ERROR_SUCCESS) {
897
String info = "Could not delete windows registry node " +
898
byteArrayToString(windowsAbsolutePath()) +
899
" at root 0x" + Integer.toHexString(rootNativeHandle()) +
900
". Windows RegDeleteKeyEx(...) returned error code " +
901
result + ".";
902
logger().warning(info);
903
throw new BackingStoreException(info);
904
}
905
closeKey(parentNativeHandle);
906
}
907
908
/**
909
* Converts value's or node's name from its byte array representation to
910
* java string. Two encodings, simple and altBase64 are used. See
911
* {@link #toWindowsName(String) toWindowsName()} for a detailed
912
* description of encoding conventions.
913
* @param windowsNameArray Null-terminated byte array.
914
*/
915
private static String toJavaName(byte[] windowsNameArray) {
916
String windowsName = byteArrayToString(windowsNameArray);
917
// check if Alt64
918
if ((windowsName.length() > 1) &&
919
(windowsName.substring(0, 2).equals("/!"))) {
920
return toJavaAlt64Name(windowsName);
921
}
922
StringBuilder javaName = new StringBuilder();
923
char ch;
924
// Decode from simple encoding
925
for (int i = 0; i < windowsName.length(); i++) {
926
if ((ch = windowsName.charAt(i)) == '/') {
927
char next = ' ';
928
if ((windowsName.length() > i + 1) &&
929
((next = windowsName.charAt(i+1)) >= 'A') &&
930
(next <= 'Z')) {
931
ch = next;
932
i++;
933
} else if ((windowsName.length() > i + 1) &&
934
(next == '/')) {
935
ch = '\\';
936
i++;
937
}
938
} else if (ch == '\\') {
939
ch = '/';
940
}
941
javaName.append(ch);
942
}
943
return javaName.toString();
944
}
945
946
/**
947
* Converts value's or node's name from its Windows representation to java
948
* string, using altBase64 encoding. See
949
* {@link #toWindowsName(String) toWindowsName()} for a detailed
950
* description of encoding conventions.
951
*/
952
953
private static String toJavaAlt64Name(String windowsName) {
954
byte[] byteBuffer =
955
Base64.altBase64ToByteArray(windowsName.substring(2));
956
StringBuilder result = new StringBuilder();
957
for (int i = 0; i < byteBuffer.length; i++) {
958
int firstbyte = (byteBuffer[i++] & 0xff);
959
int secondbyte = (byteBuffer[i] & 0xff);
960
result.append((char)((firstbyte << 8) + secondbyte));
961
}
962
return result.toString();
963
}
964
965
/**
966
* Converts value's or node's name to its Windows representation
967
* as a byte-encoded string.
968
* Two encodings, simple and altBase64 are used.
969
* <p>
970
* <i>Simple</i> encoding is used, if java string does not contain
971
* any characters less, than 0x0020, or greater, than 0x007f.
972
* Simple encoding adds "/" character to capital letters, i.e.
973
* "A" is encoded as "/A". Character '\' is encoded as '//',
974
* '/' is encoded as '\'.
975
* The constructed string is converted to byte array by truncating the
976
* highest byte and adding the terminating <tt>null</tt> character.
977
* <p>
978
* <i>altBase64</i> encoding is used, if java string does contain at least
979
* one character less, than 0x0020, or greater, than 0x007f.
980
* This encoding is marked by setting first two bytes of the
981
* Windows string to '/!'. The java name is then encoded using
982
* byteArrayToAltBase64() method from
983
* Base64 class.
984
*/
985
private static byte[] toWindowsName(String javaName) {
986
StringBuilder windowsName = new StringBuilder();
987
for (int i = 0; i < javaName.length(); i++) {
988
char ch = javaName.charAt(i);
989
if ((ch < 0x0020) || (ch > 0x007f)) {
990
// If a non-trivial character encountered, use altBase64
991
return toWindowsAlt64Name(javaName);
992
}
993
if (ch == '\\') {
994
windowsName.append("//");
995
} else if (ch == '/') {
996
windowsName.append('\\');
997
} else if ((ch >= 'A') && (ch <='Z')) {
998
windowsName.append('/').append(ch);
999
} else {
1000
windowsName.append(ch);
1001
}
1002
}
1003
return stringToByteArray(windowsName.toString());
1004
}
1005
1006
/**
1007
* Converts value's or node's name to its Windows representation
1008
* as a byte-encoded string, using altBase64 encoding. See
1009
* {@link #toWindowsName(String) toWindowsName()} for a detailed
1010
* description of encoding conventions.
1011
*/
1012
private static byte[] toWindowsAlt64Name(String javaName) {
1013
byte[] javaNameArray = new byte[2*javaName.length()];
1014
// Convert to byte pairs
1015
int counter = 0;
1016
for (int i = 0; i < javaName.length();i++) {
1017
int ch = javaName.charAt(i);
1018
javaNameArray[counter++] = (byte)(ch >>> 8);
1019
javaNameArray[counter++] = (byte)ch;
1020
}
1021
1022
return stringToByteArray("/!" +
1023
Base64.byteArrayToAltBase64(javaNameArray));
1024
}
1025
1026
/**
1027
* Converts value string from its Windows representation
1028
* to java string. See
1029
* {@link #toWindowsValueString(String) toWindowsValueString()} for the
1030
* description of the encoding algorithm.
1031
*/
1032
private static String toJavaValueString(byte[] windowsNameArray) {
1033
// Use modified native2ascii algorithm
1034
String windowsName = byteArrayToString(windowsNameArray);
1035
StringBuilder javaName = new StringBuilder();
1036
char ch;
1037
for (int i = 0; i < windowsName.length(); i++){
1038
if ((ch = windowsName.charAt(i)) == '/') {
1039
char next = ' ';
1040
1041
if (windowsName.length() > i + 1 &&
1042
(next = windowsName.charAt(i + 1)) == 'u') {
1043
if (windowsName.length() < i + 6) {
1044
break;
1045
} else {
1046
ch = (char)Integer.parseInt(
1047
windowsName.substring(i + 2, i + 6), 16);
1048
i += 5;
1049
}
1050
} else
1051
if ((windowsName.length() > i + 1) &&
1052
((windowsName.charAt(i+1)) >= 'A') &&
1053
(next <= 'Z')) {
1054
ch = next;
1055
i++;
1056
} else if ((windowsName.length() > i + 1) &&
1057
(next == '/')) {
1058
ch = '\\';
1059
i++;
1060
}
1061
} else if (ch == '\\') {
1062
ch = '/';
1063
}
1064
javaName.append(ch);
1065
}
1066
return javaName.toString();
1067
}
1068
1069
/**
1070
* Converts value string to it Windows representation.
1071
* as a byte-encoded string.
1072
* Encoding algorithm adds "/" character to capital letters, i.e.
1073
* "A" is encoded as "/A". Character '\' is encoded as '//',
1074
* '/' is encoded as '\'.
1075
* Then encoding scheme similar to jdk's native2ascii converter is used
1076
* to convert java string to a byte array of ASCII characters.
1077
*/
1078
private static byte[] toWindowsValueString(String javaName) {
1079
StringBuilder windowsName = new StringBuilder();
1080
for (int i = 0; i < javaName.length(); i++) {
1081
char ch = javaName.charAt(i);
1082
if ((ch < 0x0020) || (ch > 0x007f)){
1083
// write \udddd
1084
windowsName.append("/u");
1085
String hex = Integer.toHexString(javaName.charAt(i));
1086
StringBuilder hex4 = new StringBuilder(hex);
1087
hex4.reverse();
1088
int len = 4 - hex4.length();
1089
for (int j = 0; j < len; j++){
1090
hex4.append('0');
1091
}
1092
for (int j = 0; j < 4; j++){
1093
windowsName.append(hex4.charAt(3 - j));
1094
}
1095
} else if (ch == '\\') {
1096
windowsName.append("//");
1097
} else if (ch == '/') {
1098
windowsName.append('\\');
1099
} else if ((ch >= 'A') && (ch <='Z')) {
1100
windowsName.append('/').append(ch);
1101
} else {
1102
windowsName.append(ch);
1103
}
1104
}
1105
return stringToByteArray(windowsName.toString());
1106
}
1107
1108
/**
1109
* Returns native handle for the top Windows node for this node.
1110
*/
1111
private int rootNativeHandle() {
1112
return (isUserNode()
1113
? USER_ROOT_NATIVE_HANDLE
1114
: SYSTEM_ROOT_NATIVE_HANDLE);
1115
}
1116
1117
/**
1118
* Returns this java string as a null-terminated byte array
1119
*/
1120
private static byte[] stringToByteArray(String str) {
1121
byte[] result = new byte[str.length()+1];
1122
for (int i = 0; i < str.length(); i++) {
1123
result[i] = (byte) str.charAt(i);
1124
}
1125
result[str.length()] = 0;
1126
return result;
1127
}
1128
1129
/**
1130
* Converts a null-terminated byte array to java string
1131
*/
1132
private static String byteArrayToString(byte[] array) {
1133
StringBuilder result = new StringBuilder();
1134
for (int i = 0; i < array.length - 1; i++) {
1135
result.append((char)array[i]);
1136
}
1137
return result.toString();
1138
}
1139
1140
/**
1141
* Empty, never used implementation of AbstractPreferences.flushSpi().
1142
*/
1143
protected void flushSpi() throws BackingStoreException {
1144
// assert false;
1145
}
1146
1147
/**
1148
* Empty, never used implementation of AbstractPreferences.flushSpi().
1149
*/
1150
protected void syncSpi() throws BackingStoreException {
1151
// assert false;
1152
}
1153
1154
private static synchronized PlatformLogger logger() {
1155
if (logger == null) {
1156
logger = PlatformLogger.getLogger("java.util.prefs");
1157
}
1158
return logger;
1159
}
1160
}
1161
1162