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/sun/awt/shell/Win32ShellFolderManager2.java
32288 views
1
/*
2
* Copyright (c) 2003, 2019, 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 sun.awt.shell;
27
28
import java.awt.Image;
29
import java.awt.Toolkit;
30
import java.awt.image.BufferedImage;
31
32
import java.io.File;
33
import java.io.FileNotFoundException;
34
import java.io.IOException;
35
import java.security.AccessController;
36
import java.security.PrivilegedAction;
37
import java.util.ArrayList;
38
import java.util.Arrays;
39
import java.util.List;
40
import java.util.concurrent.Callable;
41
import java.util.concurrent.ExecutionException;
42
import java.util.concurrent.Future;
43
import java.util.concurrent.LinkedBlockingQueue;
44
import java.util.concurrent.RejectedExecutionException;
45
import java.util.concurrent.ThreadFactory;
46
import java.util.concurrent.ThreadPoolExecutor;
47
import java.util.concurrent.TimeUnit;
48
import java.util.stream.Stream;
49
50
import sun.awt.OSInfo;
51
import sun.misc.ThreadGroupUtils;
52
import sun.util.logging.PlatformLogger;
53
54
import static sun.awt.shell.Win32ShellFolder2.DESKTOP;
55
import static sun.awt.shell.Win32ShellFolder2.DRIVES;
56
import static sun.awt.shell.Win32ShellFolder2.Invoker;
57
import static sun.awt.shell.Win32ShellFolder2.NETWORK;
58
import static sun.awt.shell.Win32ShellFolder2.PERSONAL;
59
import static sun.awt.shell.Win32ShellFolder2.RECENT;
60
61
// NOTE: This class supersedes Win32ShellFolderManager, which was removed
62
// from distribution after version 1.4.2.
63
64
/**
65
* @author Michael Martak
66
* @author Leif Samuelsson
67
* @author Kenneth Russell
68
* @since 1.4
69
*/
70
71
public class Win32ShellFolderManager2 extends ShellFolderManager {
72
73
private static final PlatformLogger
74
log = PlatformLogger.getLogger("sun.awt.shell.Win32ShellFolderManager2");
75
76
static {
77
// Load library here
78
sun.awt.windows.WToolkit.loadLibraries();
79
}
80
81
public ShellFolder createShellFolder(File file) throws FileNotFoundException {
82
try {
83
return createShellFolder(getDesktop(), file);
84
} catch (InterruptedException e) {
85
throw new FileNotFoundException("Execution was interrupted");
86
}
87
}
88
89
static Win32ShellFolder2 createShellFolder(Win32ShellFolder2 parent, File file)
90
throws FileNotFoundException, InterruptedException {
91
long pIDL;
92
try {
93
pIDL = parent.parseDisplayName(file.getCanonicalPath());
94
} catch (IOException ex) {
95
pIDL = 0;
96
}
97
if (pIDL == 0) {
98
// Shouldn't happen but watch for it anyway
99
throw new FileNotFoundException("File " + file.getAbsolutePath() + " not found");
100
}
101
102
try {
103
return createShellFolderFromRelativePIDL(parent, pIDL);
104
} finally {
105
Win32ShellFolder2.releasePIDL(pIDL);
106
}
107
}
108
109
static Win32ShellFolder2 createShellFolderFromRelativePIDL(Win32ShellFolder2 parent, long pIDL)
110
throws InterruptedException {
111
// Walk down this relative pIDL, creating new nodes for each of the entries
112
while (pIDL != 0) {
113
long curPIDL = Win32ShellFolder2.copyFirstPIDLEntry(pIDL);
114
if (curPIDL != 0) {
115
parent = new Win32ShellFolder2(parent, curPIDL);
116
pIDL = Win32ShellFolder2.getNextPIDLEntry(pIDL);
117
} else {
118
// The list is empty if the parent is Desktop and pIDL is a shortcut to Desktop
119
break;
120
}
121
}
122
return parent;
123
}
124
125
private static final int VIEW_LIST = 2;
126
private static final int VIEW_DETAILS = 3;
127
private static final int VIEW_PARENTFOLDER = 8;
128
private static final int VIEW_NEWFOLDER = 11;
129
130
private static final Image[] STANDARD_VIEW_BUTTONS = new Image[12];
131
132
private static Image getStandardViewButton(int iconIndex) {
133
Image result = STANDARD_VIEW_BUTTONS[iconIndex];
134
135
if (result != null) {
136
return result;
137
}
138
139
BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
140
141
img.setRGB(0, 0, 16, 16, Win32ShellFolder2.getStandardViewButton0(iconIndex), 0, 16);
142
143
STANDARD_VIEW_BUTTONS[iconIndex] = img;
144
145
return img;
146
}
147
148
// Special folders
149
private static Win32ShellFolder2 desktop;
150
private static Win32ShellFolder2 drives;
151
private static Win32ShellFolder2 recent;
152
private static Win32ShellFolder2 network;
153
private static Win32ShellFolder2 personal;
154
155
static Win32ShellFolder2 getDesktop() {
156
if (desktop == null) {
157
try {
158
desktop = new Win32ShellFolder2(DESKTOP);
159
} catch (final SecurityException ignored) {
160
// Ignore, the message may have sensitive information, not
161
// accessible other ways
162
} catch (IOException | InterruptedException e) {
163
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
164
log.warning("Cannot access 'Desktop'", e);
165
}
166
}
167
}
168
return desktop;
169
}
170
171
static Win32ShellFolder2 getDrives() {
172
if (drives == null) {
173
try {
174
drives = new Win32ShellFolder2(DRIVES);
175
} catch (final SecurityException ignored) {
176
// Ignore, the message may have sensitive information, not
177
// accessible other ways
178
} catch (IOException | InterruptedException e) {
179
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
180
log.warning("Cannot access 'Drives'", e);
181
}
182
}
183
}
184
return drives;
185
}
186
187
static Win32ShellFolder2 getRecent() {
188
if (recent == null) {
189
try {
190
String path = Win32ShellFolder2.getFileSystemPath(RECENT);
191
if (path != null) {
192
recent = createShellFolder(getDesktop(), new File(path));
193
}
194
} catch (final SecurityException ignored) {
195
// Ignore, the message may have sensitive information, not
196
// accessible other ways
197
} catch (InterruptedException | IOException e) {
198
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
199
log.warning("Cannot access 'Recent'", e);
200
}
201
}
202
}
203
return recent;
204
}
205
206
static Win32ShellFolder2 getNetwork() {
207
if (network == null) {
208
try {
209
network = new Win32ShellFolder2(NETWORK);
210
} catch (final SecurityException ignored) {
211
// Ignore, the message may have sensitive information, not
212
// accessible other ways
213
} catch (IOException | InterruptedException e) {
214
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
215
log.warning("Cannot access 'Network'", e);
216
}
217
}
218
}
219
return network;
220
}
221
222
static Win32ShellFolder2 getPersonal() {
223
if (personal == null) {
224
try {
225
String path = Win32ShellFolder2.getFileSystemPath(PERSONAL);
226
if (path != null) {
227
Win32ShellFolder2 desktop = getDesktop();
228
personal = desktop.getChildByPath(path);
229
if (personal == null) {
230
personal = createShellFolder(getDesktop(), new File(path));
231
}
232
if (personal != null) {
233
personal.setIsPersonal();
234
}
235
}
236
} catch (final SecurityException ignored) {
237
// Ignore, the message may have sensitive information, not
238
// accessible other ways
239
} catch (InterruptedException | IOException e) {
240
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
241
log.warning("Cannot access 'Personal'", e);
242
}
243
}
244
}
245
return personal;
246
}
247
248
249
private static File[] roots;
250
251
/**
252
* @param key a <code>String</code>
253
* "fileChooserDefaultFolder":
254
* Returns a <code>File</code> - the default shellfolder for a new filechooser
255
* "roots":
256
* Returns a <code>File[]</code> - containing the root(s) of the displayable hierarchy
257
* "fileChooserComboBoxFolders":
258
* Returns a <code>File[]</code> - an array of shellfolders representing the list to
259
* show by default in the file chooser's combobox
260
* "fileChooserShortcutPanelFolders":
261
* Returns a <code>File[]</code> - an array of shellfolders representing well-known
262
* folders, such as Desktop, Documents, History, Network, Home, etc.
263
* This is used in the shortcut panel of the filechooser on Windows 2000
264
* and Windows Me.
265
* "fileChooserIcon <icon>":
266
* Returns an <code>Image</code> - icon can be ListView, DetailsView, UpFolder, NewFolder or
267
* ViewMenu (Windows only).
268
* "optionPaneIcon iconName":
269
* Returns an <code>Image</code> - icon from the system icon list
270
*
271
* @return An Object matching the key string.
272
*/
273
public Object get(String key) {
274
if (key.equals("fileChooserDefaultFolder")) {
275
File file = getPersonal();
276
if (file == null) {
277
file = getDesktop();
278
}
279
return checkFile(file);
280
} else if (key.equals("roots")) {
281
// Should be "History" and "Desktop" ?
282
if (roots == null) {
283
File desktop = getDesktop();
284
if (desktop != null) {
285
roots = new File[] { desktop };
286
} else {
287
roots = (File[])super.get(key);
288
}
289
}
290
return checkFiles(roots);
291
} else if (key.equals("fileChooserComboBoxFolders")) {
292
Win32ShellFolder2 desktop = getDesktop();
293
294
if (desktop != null && checkFile(desktop) != null) {
295
ArrayList<File> folders = new ArrayList<File>();
296
Win32ShellFolder2 drives = getDrives();
297
298
Win32ShellFolder2 recentFolder = getRecent();
299
if (recentFolder != null && OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_2000) >= 0) {
300
folders.add(recentFolder);
301
}
302
303
folders.add(desktop);
304
// Add all second level folders
305
File[] secondLevelFolders = checkFiles(desktop.listFiles());
306
Arrays.sort(secondLevelFolders);
307
for (File secondLevelFolder : secondLevelFolders) {
308
Win32ShellFolder2 folder = (Win32ShellFolder2) secondLevelFolder;
309
if (!folder.isFileSystem() || (folder.isDirectory() && !folder.isLink())) {
310
folders.add(folder);
311
// Add third level for "My Computer"
312
if (folder.equals(drives)) {
313
File[] thirdLevelFolders = checkFiles(folder.listFiles());
314
if (thirdLevelFolders != null && thirdLevelFolders.length > 0) {
315
List<File> thirdLevelFoldersList = Arrays.asList(thirdLevelFolders);
316
317
folder.sortChildren(thirdLevelFoldersList);
318
folders.addAll(thirdLevelFoldersList);
319
}
320
}
321
}
322
}
323
return checkFiles(folders);
324
} else {
325
return super.get(key);
326
}
327
} else if (key.equals("fileChooserShortcutPanelFolders")) {
328
Toolkit toolkit = Toolkit.getDefaultToolkit();
329
ArrayList<File> folders = new ArrayList<File>();
330
int i = 0;
331
Object value;
332
do {
333
value = toolkit.getDesktopProperty("win.comdlg.placesBarPlace" + i++);
334
try {
335
if (value instanceof Integer) {
336
// A CSIDL
337
folders.add(new Win32ShellFolder2((Integer)value));
338
} else if (value instanceof String) {
339
// A path
340
folders.add(createShellFolder(new File((String)value)));
341
}
342
} catch (IOException e) {
343
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
344
log.warning("Cannot read value = " + value, e);
345
}
346
// Skip this value
347
} catch (InterruptedException e) {
348
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
349
log.warning("Cannot read value = " + value, e);
350
}
351
// Return empty result
352
return new File[0];
353
}
354
} while (value != null);
355
356
if (folders.size() == 0) {
357
// Use default list of places
358
for (File f : new File[] {
359
getRecent(), getDesktop(), getPersonal(), getDrives(), getNetwork()
360
}) {
361
if (f != null) {
362
folders.add(f);
363
}
364
}
365
}
366
return checkFiles(folders);
367
} else if (key.startsWith("fileChooserIcon ")) {
368
String name = key.substring(key.indexOf(" ") + 1);
369
370
int iconIndex;
371
372
if (name.equals("ListView") || name.equals("ViewMenu")) {
373
iconIndex = VIEW_LIST;
374
} else if (name.equals("DetailsView")) {
375
iconIndex = VIEW_DETAILS;
376
} else if (name.equals("UpFolder")) {
377
iconIndex = VIEW_PARENTFOLDER;
378
} else if (name.equals("NewFolder")) {
379
iconIndex = VIEW_NEWFOLDER;
380
} else {
381
return null;
382
}
383
384
return getStandardViewButton(iconIndex);
385
} else if (key.startsWith("optionPaneIcon ")) {
386
Win32ShellFolder2.SystemIcon iconType;
387
if (key == "optionPaneIcon Error") {
388
iconType = Win32ShellFolder2.SystemIcon.IDI_ERROR;
389
} else if (key == "optionPaneIcon Information") {
390
iconType = Win32ShellFolder2.SystemIcon.IDI_INFORMATION;
391
} else if (key == "optionPaneIcon Question") {
392
iconType = Win32ShellFolder2.SystemIcon.IDI_QUESTION;
393
} else if (key == "optionPaneIcon Warning") {
394
iconType = Win32ShellFolder2.SystemIcon.IDI_EXCLAMATION;
395
} else {
396
return null;
397
}
398
return Win32ShellFolder2.getSystemIcon(iconType);
399
} else if (key.startsWith("shell32Icon ") || key.startsWith("shell32LargeIcon ")) {
400
String name = key.substring(key.indexOf(" ") + 1);
401
try {
402
int i = Integer.parseInt(name);
403
if (i >= 0) {
404
return Win32ShellFolder2.getShell32Icon(i, key.startsWith("shell32LargeIcon "));
405
}
406
} catch (NumberFormatException ex) {
407
}
408
}
409
return null;
410
}
411
412
private static File checkFile(File file) {
413
SecurityManager sm = System.getSecurityManager();
414
return (sm == null || file == null) ? file : checkFile(file, sm);
415
}
416
417
private static File checkFile(File file, SecurityManager sm) {
418
try {
419
sm.checkRead(file.getPath());
420
421
if (file instanceof Win32ShellFolder2) {
422
Win32ShellFolder2 f = (Win32ShellFolder2)file;
423
if (f.isLink()) {
424
Win32ShellFolder2 link = (Win32ShellFolder2)f.getLinkLocation();
425
if (link != null)
426
sm.checkRead(link.getPath());
427
}
428
}
429
return file;
430
} catch (SecurityException se) {
431
return null;
432
}
433
}
434
435
static File[] checkFiles(File[] files) {
436
SecurityManager sm = System.getSecurityManager();
437
if (sm == null || files == null || files.length == 0) {
438
return files;
439
}
440
return checkFiles(Arrays.stream(files), sm);
441
}
442
443
private static File[] checkFiles(List<File> files) {
444
SecurityManager sm = System.getSecurityManager();
445
if (sm == null || files.isEmpty()) {
446
return files.toArray(new File[files.size()]);
447
}
448
return checkFiles(files.stream(), sm);
449
}
450
451
private static File[] checkFiles(Stream<File> filesStream, SecurityManager sm) {
452
return filesStream.filter((file) -> checkFile(file, sm) != null)
453
.toArray(File[]::new);
454
}
455
456
/**
457
* Does <code>dir</code> represent a "computer" such as a node on the network, or
458
* "My Computer" on the desktop.
459
*/
460
public boolean isComputerNode(final File dir) {
461
if (dir != null && dir == getDrives()) {
462
return true;
463
} else {
464
String path = AccessController.doPrivileged(new PrivilegedAction<String>() {
465
public String run() {
466
return dir.getAbsolutePath();
467
}
468
});
469
470
return (path.startsWith("\\\\") && path.indexOf("\\", 2) < 0); //Network path
471
}
472
}
473
474
public boolean isFileSystemRoot(File dir) {
475
//Note: Removable drives don't "exist" but are listed in "My Computer"
476
if (dir != null) {
477
Win32ShellFolder2 drives = getDrives();
478
if (dir instanceof Win32ShellFolder2) {
479
Win32ShellFolder2 sf = (Win32ShellFolder2)dir;
480
if (sf.isFileSystem()) {
481
if (sf.parent != null) {
482
return sf.parent.equals(drives);
483
}
484
// else fall through ...
485
} else {
486
return false;
487
}
488
}
489
String path = dir.getPath();
490
491
if (path.length() != 3 || path.charAt(1) != ':') {
492
return false;
493
}
494
495
File[] files = drives.listFiles();
496
497
return files != null && Arrays.asList(files).contains(dir);
498
}
499
return false;
500
}
501
502
private static List topFolderList = null;
503
static int compareShellFolders(Win32ShellFolder2 sf1, Win32ShellFolder2 sf2) {
504
boolean special1 = sf1.isSpecial();
505
boolean special2 = sf2.isSpecial();
506
507
if (special1 || special2) {
508
if (topFolderList == null) {
509
ArrayList tmpTopFolderList = new ArrayList();
510
tmpTopFolderList.add(Win32ShellFolderManager2.getPersonal());
511
tmpTopFolderList.add(Win32ShellFolderManager2.getDesktop());
512
tmpTopFolderList.add(Win32ShellFolderManager2.getDrives());
513
tmpTopFolderList.add(Win32ShellFolderManager2.getNetwork());
514
topFolderList = tmpTopFolderList;
515
}
516
int i1 = topFolderList.indexOf(sf1);
517
int i2 = topFolderList.indexOf(sf2);
518
if (i1 >= 0 && i2 >= 0) {
519
return (i1 - i2);
520
} else if (i1 >= 0) {
521
return -1;
522
} else if (i2 >= 0) {
523
return 1;
524
}
525
}
526
527
// Non-file shellfolders sort before files
528
if (special1 && !special2) {
529
return -1;
530
} else if (special2 && !special1) {
531
return 1;
532
}
533
534
return compareNames(sf1.getAbsolutePath(), sf2.getAbsolutePath());
535
}
536
537
static int compareNames(String name1, String name2) {
538
// First ignore case when comparing
539
int diff = name1.compareToIgnoreCase(name2);
540
if (diff != 0) {
541
return diff;
542
} else {
543
// May differ in case (e.g. "mail" vs. "Mail")
544
// We need this test for consistent sorting
545
return name1.compareTo(name2);
546
}
547
}
548
549
@Override
550
protected Invoker createInvoker() {
551
return new ComInvoker();
552
}
553
554
private static class ComInvoker extends ThreadPoolExecutor implements ThreadFactory, ShellFolder.Invoker {
555
private static Thread comThread;
556
557
private ComInvoker() {
558
super(1, 1, 0, TimeUnit.DAYS, new LinkedBlockingQueue<Runnable>());
559
allowCoreThreadTimeOut(false);
560
setThreadFactory(this);
561
final Runnable shutdownHook = new Runnable() {
562
public void run() {
563
AccessController.doPrivileged(new PrivilegedAction<Void>() {
564
public Void run() {
565
shutdownNow();
566
return null;
567
}
568
});
569
}
570
};
571
AccessController.doPrivileged(new PrivilegedAction<Void>() {
572
public Void run() {
573
Runtime.getRuntime().addShutdownHook(
574
new Thread(shutdownHook)
575
);
576
return null;
577
}
578
});
579
}
580
581
public synchronized Thread newThread(final Runnable task) {
582
final Runnable comRun = new Runnable() {
583
public void run() {
584
try {
585
initializeCom();
586
task.run();
587
} finally {
588
uninitializeCom();
589
}
590
}
591
};
592
comThread = AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
593
/* The thread must be a member of a thread group
594
* which will not get GCed before VM exit.
595
* Make its parent the top-level thread group.
596
*/
597
ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup();
598
Thread thread = new Thread(rootTG, comRun, "Swing-Shell");
599
thread.setDaemon(true);
600
return thread;
601
}
602
);
603
return comThread;
604
}
605
606
public <T> T invoke(Callable<T> task) throws Exception {
607
if (Thread.currentThread() == comThread) {
608
// if it's already called from the COM
609
// thread, we don't need to delegate the task
610
return task.call();
611
} else {
612
final Future<T> future;
613
614
try {
615
future = submit(task);
616
} catch (RejectedExecutionException e) {
617
throw new InterruptedException(e.getMessage());
618
}
619
620
try {
621
return future.get();
622
} catch (InterruptedException e) {
623
AccessController.doPrivileged(new PrivilegedAction<Void>() {
624
public Void run() {
625
future.cancel(true);
626
627
return null;
628
}
629
});
630
631
throw e;
632
} catch (ExecutionException e) {
633
Throwable cause = e.getCause();
634
635
if (cause instanceof Exception) {
636
throw (Exception) cause;
637
}
638
639
if (cause instanceof Error) {
640
throw (Error) cause;
641
}
642
643
throw new RuntimeException("Unexpected error", cause);
644
}
645
}
646
}
647
}
648
649
static native void initializeCom();
650
651
static native void uninitializeCom();
652
}
653
654