package sun.awt.shell;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.BaseMultiResolutionImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Stream;
import static sun.awt.shell.Win32ShellFolder2.*;
import sun.awt.OSInfo;
import sun.awt.util.ThreadGroupUtils;
final class Win32ShellFolderManager2 extends ShellFolderManager {
static {
sun.awt.windows.WToolkit.loadLibraries();
}
public ShellFolder createShellFolder(File file) throws FileNotFoundException {
try {
return createShellFolder(getDesktop(), file);
} catch (InterruptedException e) {
throw new FileNotFoundException("Execution was interrupted");
}
}
static Win32ShellFolder2 createShellFolder(Win32ShellFolder2 parent, File file)
throws FileNotFoundException, InterruptedException {
long pIDL;
try {
pIDL = parent.parseDisplayName(file.getCanonicalPath());
} catch (IOException ex) {
pIDL = 0;
}
if (pIDL == 0) {
throw new FileNotFoundException("File " + file.getAbsolutePath() + " not found");
}
try {
return createShellFolderFromRelativePIDL(parent, pIDL);
} finally {
Win32ShellFolder2.releasePIDL(pIDL);
}
}
static Win32ShellFolder2 createShellFolderFromRelativePIDL(Win32ShellFolder2 parent, long pIDL)
throws InterruptedException {
while (pIDL != 0) {
long curPIDL = Win32ShellFolder2.copyFirstPIDLEntry(pIDL);
if (curPIDL != 0) {
parent = Win32ShellFolder2.createShellFolder(parent, curPIDL);
pIDL = Win32ShellFolder2.getNextPIDLEntry(pIDL);
} else {
break;
}
}
return parent;
}
private static final int VIEW_LIST = 2;
private static final int VIEW_DETAILS = 3;
private static final int VIEW_PARENTFOLDER = 8;
private static final int VIEW_NEWFOLDER = 11;
private static final Image[] STANDARD_VIEW_BUTTONS = new Image[12];
private static Image getStandardViewButton(int iconIndex) {
Image result = STANDARD_VIEW_BUTTONS[iconIndex];
if (result != null) {
return result;
}
final int[] iconBits = Win32ShellFolder2
.getStandardViewButton0(iconIndex, true);
if (iconBits != null) {
final int size = (int) Math.sqrt(iconBits.length);
final BufferedImage img =
new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, size, size, iconBits, 0, size);
STANDARD_VIEW_BUTTONS[iconIndex] = (size == 16)
? img
: new MultiResolutionIconImage(16, img);
}
return STANDARD_VIEW_BUTTONS[iconIndex];
}
private static Win32ShellFolder2 desktop;
private static Win32ShellFolder2 drives;
private static Win32ShellFolder2 recent;
private static Win32ShellFolder2 network;
private static Win32ShellFolder2 personal;
static Win32ShellFolder2 getDesktop() {
if (desktop == null) {
try {
desktop = new Win32ShellFolder2(DESKTOP);
} catch (SecurityException e) {
} catch (IOException e) {
} catch (InterruptedException e) {
}
}
return desktop;
}
static Win32ShellFolder2 getDrives() {
if (drives == null) {
try {
drives = new Win32ShellFolder2(DRIVES);
} catch (SecurityException e) {
} catch (IOException e) {
} catch (InterruptedException e) {
}
}
return drives;
}
static Win32ShellFolder2 getRecent() {
if (recent == null) {
try {
String path = Win32ShellFolder2.getFileSystemPath(RECENT);
if (path != null) {
recent = createShellFolder(getDesktop(), new File(path));
}
} catch (SecurityException e) {
} catch (InterruptedException e) {
} catch (IOException e) {
}
}
return recent;
}
static Win32ShellFolder2 getNetwork() {
if (network == null) {
try {
network = new Win32ShellFolder2(NETWORK);
} catch (SecurityException e) {
} catch (IOException e) {
} catch (InterruptedException e) {
}
}
return network;
}
static Win32ShellFolder2 getPersonal() {
if (personal == null) {
try {
String path = Win32ShellFolder2.getFileSystemPath(PERSONAL);
if (path != null) {
Win32ShellFolder2 desktop = getDesktop();
personal = desktop.getChildByPath(path);
if (personal == null) {
personal = createShellFolder(getDesktop(), new File(path));
}
if (personal != null) {
personal.setIsPersonal();
}
}
} catch (SecurityException e) {
} catch (InterruptedException e) {
} catch (IOException e) {
}
}
return personal;
}
private static File[] roots;
public Object get(String key) {
if (key.equals("fileChooserDefaultFolder")) {
File file = getPersonal();
if (file == null) {
file = getDesktop();
}
return checkFile(file);
} else if (key.equals("roots")) {
if (roots == null) {
File desktop = getDesktop();
if (desktop != null) {
roots = new File[] { desktop };
} else {
roots = (File[])super.get(key);
}
}
return checkFiles(roots);
} else if (key.equals("fileChooserComboBoxFolders")) {
Win32ShellFolder2 desktop = getDesktop();
if (desktop != null && checkFile(desktop) != null) {
ArrayList<File> folders = new ArrayList<File>();
Win32ShellFolder2 drives = getDrives();
Win32ShellFolder2 recentFolder = getRecent();
if (recentFolder != null && OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_2000) >= 0) {
folders.add(recentFolder);
}
folders.add(desktop);
File[] secondLevelFolders = checkFiles(desktop.listFiles());
Arrays.sort(secondLevelFolders);
for (File secondLevelFolder : secondLevelFolders) {
Win32ShellFolder2 folder = (Win32ShellFolder2) secondLevelFolder;
if (!folder.isFileSystem() || (folder.isDirectory() && !folder.isLink())) {
folders.add(folder);
if (folder.equals(drives)) {
File[] thirdLevelFolders = checkFiles(folder.listFiles());
if (thirdLevelFolders != null && thirdLevelFolders.length > 0) {
List<File> thirdLevelFoldersList = Arrays.asList(thirdLevelFolders);
folder.sortChildren(thirdLevelFoldersList);
folders.addAll(thirdLevelFoldersList);
}
}
}
}
return checkFiles(folders);
} else {
return super.get(key);
}
} else if (key.equals("fileChooserShortcutPanelFolders")) {
Toolkit toolkit = Toolkit.getDefaultToolkit();
ArrayList<File> folders = new ArrayList<File>();
int i = 0;
Object value;
do {
value = toolkit.getDesktopProperty("win.comdlg.placesBarPlace" + i++);
try {
if (value instanceof Integer) {
folders.add(new Win32ShellFolder2((Integer)value));
} else if (value instanceof String) {
folders.add(createShellFolder(new File((String)value)));
}
} catch (IOException e) {
} catch (InterruptedException e) {
return new File[0];
}
} while (value != null);
if (folders.size() == 0) {
for (File f : new File[] {
getRecent(), getDesktop(), getPersonal(), getDrives(), getNetwork()
}) {
if (f != null) {
folders.add(f);
}
}
}
return checkFiles(folders);
} else if (key.startsWith("fileChooserIcon ")) {
String name = key.substring(key.indexOf(" ") + 1);
int iconIndex;
if (name.equals("ListView") || name.equals("ViewMenu")) {
iconIndex = VIEW_LIST;
} else if (name.equals("DetailsView")) {
iconIndex = VIEW_DETAILS;
} else if (name.equals("UpFolder")) {
iconIndex = VIEW_PARENTFOLDER;
} else if (name.equals("NewFolder")) {
iconIndex = VIEW_NEWFOLDER;
} else {
return null;
}
return getStandardViewButton(iconIndex);
} else if (key.startsWith("optionPaneIcon ")) {
Win32ShellFolder2.SystemIcon iconType;
if (key == "optionPaneIcon Error") {
iconType = Win32ShellFolder2.SystemIcon.IDI_ERROR;
} else if (key == "optionPaneIcon Information") {
iconType = Win32ShellFolder2.SystemIcon.IDI_INFORMATION;
} else if (key == "optionPaneIcon Question") {
iconType = Win32ShellFolder2.SystemIcon.IDI_QUESTION;
} else if (key == "optionPaneIcon Warning") {
iconType = Win32ShellFolder2.SystemIcon.IDI_EXCLAMATION;
} else {
return null;
}
return Win32ShellFolder2.getSystemIcon(iconType);
} else if (key.startsWith("shell32Icon ") || key.startsWith("shell32LargeIcon ")) {
String name = key.substring(key.indexOf(" ") + 1);
try {
int i = Integer.parseInt(name);
if (i >= 0) {
return Win32ShellFolder2.getShell32Icon(i, key.startsWith("shell32LargeIcon "));
}
} catch (NumberFormatException ex) {
}
}
return null;
}
private File checkFile(File file) {
SecurityManager sm = System.getSecurityManager();
return (sm == null || file == null) ? file : checkFile(file, sm);
}
private File checkFile(File file, SecurityManager sm) {
try {
sm.checkRead(file.getPath());
return file;
} catch (SecurityException se) {
return null;
}
}
private File[] checkFiles(File[] files) {
SecurityManager sm = System.getSecurityManager();
if (sm == null || files == null || files.length == 0) {
return files;
}
return checkFiles(Arrays.stream(files), sm);
}
private File[] checkFiles(List<File> files) {
SecurityManager sm = System.getSecurityManager();
if (sm == null || files.isEmpty()) {
return files.toArray(new File[files.size()]);
}
return checkFiles(files.stream(), sm);
}
private File[] checkFiles(Stream<File> filesStream, SecurityManager sm) {
return filesStream.filter((file) -> checkFile(file, sm) != null)
.toArray(File[]::new);
}
public boolean isComputerNode(final File dir) {
if (dir != null && dir == getDrives()) {
return true;
} else {
String path = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return dir.getAbsolutePath();
}
});
return (path.startsWith("\\\\") && path.indexOf("\\", 2) < 0);
}
}
public boolean isFileSystemRoot(File dir) {
if (dir != null) {
if (dir instanceof Win32ShellFolder2) {
Win32ShellFolder2 sf = (Win32ShellFolder2)dir;
return (sf.isFileSystem() && sf.parent != null &&
sf.parent.equals(getDrives()));
}
String path = dir.getPath();
if (path.length() != 3 || path.charAt(1) != ':') {
return false;
}
File[] roots = Win32ShellFolder2.listRoots();
return roots != null && Arrays.asList(roots).contains(dir);
}
return false;
}
private static List<Win32ShellFolder2> topFolderList = null;
static int compareShellFolders(Win32ShellFolder2 sf1, Win32ShellFolder2 sf2) {
boolean special1 = sf1.isSpecial();
boolean special2 = sf2.isSpecial();
if (special1 || special2) {
if (topFolderList == null) {
ArrayList<Win32ShellFolder2> tmpTopFolderList = new ArrayList<>();
tmpTopFolderList.add(Win32ShellFolderManager2.getPersonal());
tmpTopFolderList.add(Win32ShellFolderManager2.getDesktop());
tmpTopFolderList.add(Win32ShellFolderManager2.getDrives());
tmpTopFolderList.add(Win32ShellFolderManager2.getNetwork());
topFolderList = tmpTopFolderList;
}
int i1 = topFolderList.indexOf(sf1);
int i2 = topFolderList.indexOf(sf2);
if (i1 >= 0 && i2 >= 0) {
return (i1 - i2);
} else if (i1 >= 0) {
return -1;
} else if (i2 >= 0) {
return 1;
}
}
if (special1 && !special2) {
return -1;
} else if (special2 && !special1) {
return 1;
}
return compareNames(sf1.getAbsolutePath(), sf2.getAbsolutePath());
}
static int compareNames(String name1, String name2) {
int diff = name1.compareToIgnoreCase(name2);
if (diff != 0) {
return diff;
} else {
return name1.compareTo(name2);
}
}
@Override
protected Invoker createInvoker() {
return new ComInvoker();
}
private static class ComInvoker extends ThreadPoolExecutor implements ThreadFactory, ShellFolder.Invoker {
private static Thread comThread;
private ComInvoker() {
super(1, 1, 0, TimeUnit.DAYS, new LinkedBlockingQueue<>());
allowCoreThreadTimeOut(false);
setThreadFactory(this);
final Runnable shutdownHook = () -> AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
shutdownNow();
return null;
});
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
Thread t = new Thread(
ThreadGroupUtils.getRootThreadGroup(), shutdownHook,
"ShellFolder", 0, false);
Runtime.getRuntime().addShutdownHook(t);
return null;
});
}
public synchronized Thread newThread(final Runnable task) {
final Runnable comRun = new Runnable() {
public void run() {
try {
initializeCom();
task.run();
} finally {
uninitializeCom();
}
}
};
comThread = AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
String name = "Swing-Shell";
Thread thread = new Thread(
ThreadGroupUtils.getRootThreadGroup(), comRun, name,
0, false);
thread.setDaemon(true);
thread.setPriority(Thread.MAX_PRIORITY);
return thread;
});
return comThread;
}
public <T> T invoke(Callable<T> task) throws Exception {
if (Thread.currentThread() == comThread) {
return task.call();
} else {
final Future<T> future;
try {
future = submit(task);
} catch (RejectedExecutionException e) {
throw new InterruptedException(e.getMessage());
}
try {
return future.get();
} catch (InterruptedException e) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
future.cancel(true);
return null;
}
});
throw e;
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof Exception) {
throw (Exception) cause;
}
if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException("Unexpected error", cause);
}
}
}
}
static native void initializeCom();
static native void uninitializeCom();
}