From c6537a783d9de0cd6c1bc8767a2f0d15205c4bed Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 30 Jan 2011 21:32:52 -0800 Subject: [PATCH] Revamped file dialog handling. --- src/com/sk89q/worldedit/LocalPlayer.java | 13 ++- src/com/sk89q/worldedit/WorldEdit.java | 50 ++++++++++- .../worldedit/commands/ClipboardCommands.java | 6 +- .../worldedit/commands/ScriptingCommands.java | 6 +- .../scripting/CraftScriptContext.java | 40 ++++++++- .../sk89q/worldedit/util/FileDialogUtil.java | 90 +++++++++++++++++++ 6 files changed, 193 insertions(+), 12 deletions(-) create mode 100644 src/com/sk89q/worldedit/util/FileDialogUtil.java diff --git a/src/com/sk89q/worldedit/LocalPlayer.java b/src/com/sk89q/worldedit/LocalPlayer.java index 8ebc0bd34..72fb9c9e0 100644 --- a/src/com/sk89q/worldedit/LocalPlayer.java +++ b/src/com/sk89q/worldedit/LocalPlayer.java @@ -543,7 +543,18 @@ public abstract class LocalPlayer { * @param extensions null to allow all * @return */ - public File openFileDialog(String[] extensions) { + public File openFileOpenDialog(String[] extensions) { + printError("File dialogs are not supported in your environment."); + return null; + } + + /** + * Open a file save dialog. + * + * @param extensions null to allow all + * @return + */ + public File openFileSaveDialog(String[] extensions) { printError("File dialogs are not supported in your environment."); return null; } diff --git a/src/com/sk89q/worldedit/WorldEdit.java b/src/com/sk89q/worldedit/WorldEdit.java index fd6c04192..97e426efc 100644 --- a/src/com/sk89q/worldedit/WorldEdit.java +++ b/src/com/sk89q/worldedit/WorldEdit.java @@ -355,15 +355,59 @@ public class WorldEdit { * @param dir sub-directory to look in * @param filename filename (user-submitted) * @param defaultExt append an extension if missing one, null to not use + * @param extensions list of extensions, null for any * @return * @throws FilenameException */ - public File getSafeFile(LocalPlayer player, File dir, String filename, - String defaultExt) throws FilenameException { + public File getSafeSaveFile(LocalPlayer player, File dir, String filename, + String defaultExt, String[] extensions) + throws FilenameException { + return getSafeFile(player, dir, filename, defaultExt, extensions, true); + } + + /** + * Gets the path to a file. This method will check to see if the filename + * has valid characters and has an extension. It also prevents directory + * traversal exploits by checking the root directory and the file directory. + * On success, a java.io.File object will be returned. + * + * @param dir sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt append an extension if missing one, null to not use + * @param extensions list of extensions, null for any + * @return + * @throws FilenameException + */ + public File getSafeOpenFile(LocalPlayer player, File dir, String filename, + String defaultExt, String[] extensions) + throws FilenameException { + return getSafeFile(player, dir, filename, defaultExt, extensions, false); + } + + /** + * Get a safe path to a file. + * + * @param player + * @param dir + * @param filename + * @param defaultExt + * @param extensions + * @param isSave + * @return + * @throws FilenameException + */ + private File getSafeFile(LocalPlayer player, File dir, String filename, + String defaultExt, String[] extensions, boolean isSave) + throws FilenameException { File f; if (filename.equals("#")) { - f = player.openFileDialog(null); + if (isSave) { + f = player.openFileSaveDialog(extensions); + } else { + f = player.openFileOpenDialog(extensions); + } + if (f == null) { throw new FileSelectionAbortedException("No file selected"); } diff --git a/src/com/sk89q/worldedit/commands/ClipboardCommands.java b/src/com/sk89q/worldedit/commands/ClipboardCommands.java index 403432f69..df82a20ad 100644 --- a/src/com/sk89q/worldedit/commands/ClipboardCommands.java +++ b/src/com/sk89q/worldedit/commands/ClipboardCommands.java @@ -181,7 +181,8 @@ public class ClipboardCommands { String filename = args.getString(0); File dir = we.getWorkingDirectoryFile(config.saveDir); - File f = we.getSafeFile(player, dir, filename, "schematic"); + File f = we.getSafeOpenFile(player, dir, filename, "schematic", + new String[] {"schematic"}); try { String filePath = f.getCanonicalPath(); @@ -218,7 +219,8 @@ public class ClipboardCommands { String filename = args.getString(0); File dir = we.getWorkingDirectoryFile(config.saveDir); - File f = we.getSafeFile(player, dir, filename, "schematic"); + File f = we.getSafeSaveFile(player, dir, filename, "schematic", + new String[] {"schematic"}); if (!dir.exists()) { if (!dir.mkdir()) { diff --git a/src/com/sk89q/worldedit/commands/ScriptingCommands.java b/src/com/sk89q/worldedit/commands/ScriptingCommands.java index 001fca03b..b92a775ea 100644 --- a/src/com/sk89q/worldedit/commands/ScriptingCommands.java +++ b/src/com/sk89q/worldedit/commands/ScriptingCommands.java @@ -48,7 +48,8 @@ public class ScriptingCommands { session.setLastScript(args.getString(0)); File dir = we.getWorkingDirectoryFile(we.getConfiguration().scriptsDir); - File f = we.getSafeFile(player, dir, args.getString(0), "js"); + File f = we.getSafeOpenFile(player, dir, args.getString(0), "js", + new String[] {"js"}); we.runScript(player, f, scriptArgs); } @@ -76,7 +77,8 @@ public class ScriptingCommands { String[] scriptArgs = args.getSlice(0); File dir = we.getWorkingDirectoryFile(we.getConfiguration().scriptsDir); - File f = we.getSafeFile(player, dir, lastScript, "js"); + File f = we.getSafeOpenFile(player, dir, lastScript, "js", + new String[] {"js"}); we.runScript(player, f, scriptArgs); diff --git a/src/com/sk89q/worldedit/scripting/CraftScriptContext.java b/src/com/sk89q/worldedit/scripting/CraftScriptContext.java index 51fb65502..138730af4 100644 --- a/src/com/sk89q/worldedit/scripting/CraftScriptContext.java +++ b/src/com/sk89q/worldedit/scripting/CraftScriptContext.java @@ -210,23 +210,55 @@ public class CraftScriptContext extends CraftScriptEnvironment { * @return * @throws FilenameException */ + @Deprecated public File getSafeFile(String folder, String filename) throws FilenameException { File dir = controller.getWorkingDirectoryFile(folder); - return controller.getSafeFile(player, dir, filename, null); + return controller.getSafeOpenFile(player, dir, filename, null, null); } /** - * This version will append an extension if one doesn't exist. + * Gets the path to a file for opening. This method will check to see if the + * filename has valid characters and has an extension. It also prevents + * directory traversal exploits by checking the root directory and the file + * directory. On success, a java.io.File object will be + * returned. + * + *

Use this method if you need to read a file from a directory.

* * @param folder sub-directory to look in * @param filename filename (user-submitted) * @param defaultExt default extension to append if there is none + * @param exts list of extensions for file open dialog, null for no filter * @return * @throws FilenameException */ - public File getSafeFile(String folder, String filename, String defaultExt) + public File getSafeOpenFile(String folder, String filename, + String defaultExt, String[] exts) throws FilenameException { File dir = controller.getWorkingDirectoryFile(folder); - return controller.getSafeFile(player, dir, filename, defaultExt); + return controller.getSafeOpenFile(player, dir, filename, defaultExt, exts); + } + + /** + * Gets the path to a file for saving. This method will check to see if the + * filename has valid characters and has an extension. It also prevents + * directory traversal exploits by checking the root directory and the file + * directory. On success, a java.io.File object will be + * returned. + * + *

Use this method if you need to read a file from a directory.

+ * + * @param folder sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt default extension to append if there is none + * @param exts list of extensions for file save dialog, null for no filter + * @return + * @throws FilenameException + */ + public File getSafeSaveFile(String folder, String filename, + String defaultExt, String[] exts) + throws FilenameException { + File dir = controller.getWorkingDirectoryFile(folder); + return controller.getSafeSaveFile(player, dir, filename, defaultExt, exts); } } diff --git a/src/com/sk89q/worldedit/util/FileDialogUtil.java b/src/com/sk89q/worldedit/util/FileDialogUtil.java new file mode 100644 index 000000000..c91e9242b --- /dev/null +++ b/src/com/sk89q/worldedit/util/FileDialogUtil.java @@ -0,0 +1,90 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.util; + +import java.io.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.swing.JFileChooser; +import javax.swing.filechooser.FileFilter; +import com.sk89q.util.StringUtil; + +public class FileDialogUtil { + public static File showSaveDialog(String[] exts) { + JFileChooser dialog = new JFileChooser(); + + if (exts != null) { + dialog.setFileFilter(new ExtensionFilter(exts)); + } + + int returnVal = dialog.showSaveDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + return dialog.getSelectedFile(); + } + + return null; + } + + public static File showOpenDialog(String[] exts) { + JFileChooser dialog = new JFileChooser(); + + if (exts != null) { + dialog.setFileFilter(new ExtensionFilter(exts)); + } + + int returnVal = dialog.showOpenDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + return dialog.getSelectedFile(); + } + + return null; + } + + private static class ExtensionFilter extends FileFilter { + private Set exts; + private String desc; + + public ExtensionFilter(String[] exts) { + this.exts = new HashSet(Arrays.asList(exts)); + + desc = StringUtil.joinString(exts, ","); + } + + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + String path = f.getPath(); + int index = path.lastIndexOf('.'); + if (index == -1 || index == path.length() - 1) { + return false; + } else { + return exts.contains(path.indexOf(index + 1)); + } + } + + public String getDescription() { + return desc; + } + } +}