--- /dev/null 2018-10-22 10:23:00.000000000 -0400 +++ new/src/demo/share/jpackager/JNLPConverter/src/jnlp/converter/JNLPConverter.java 2018-10-22 10:22:57.595628000 -0400 @@ -0,0 +1,865 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jnlp.converter; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import jnlp.converter.parser.JNLPDesc; +import jnlp.converter.parser.JNLPDesc.AssociationDesc; +import jnlp.converter.parser.JNLPDesc.IconDesc; +import jnlp.converter.parser.ResourcesDesc.JARDesc; +import jnlp.converter.parser.XMLFormat; + +public class JNLPConverter { + + private final Options options; + private JNLPDesc jnlpd = null; + private final List launchArgs = new ArrayList<>(); + + private String downloadFolder = null; + private String jnlpDownloadFolder = null; + private static String jnlpDownloadFolderStatic; + private String jarDownloadFolder = null; + private String iconDownloadFolder = null; + private String propDownloadFolder = null; + + private static String jpackagerPath = null; + + private static boolean markFileToDelete = false; + + private static final String FA_EXTENSIONS = "extension"; + private static final String FA_CONTENT_TYPE = "mime-type"; + private static final String FA_DESCRIPTION = "description"; + private static final String FA_ICON = "icon"; + + public JNLPConverter(Options options) { + this.options = options; + jnlpDownloadFolderStatic = getJnlpDownloadFolder(); + markFileToDelete = (options.keep() == null); + } + + public String [] getLaunchArgs() { + return launchArgs.toArray(new String[0]); + } + + public void convert() { + try { + loadJNLPDesc(); + downloadResources(); + validate(); + buildLaunchArgs(); + saveLaunchArgs(); + runJPackager(); + } catch (Exception ex) { + Log.error(ex.getLocalizedMessage()); + } + } + + private JNLPDesc getJNLPD(String jnlp) throws Exception { + URL codebase = getCodeBase(jnlp); + byte[] bits = HTTPHelper.getJNLPBits(jnlp, jnlp); + return XMLFormat.parse(bits, codebase, jnlp); + } + + private void loadJNLPDesc() throws Exception { + String jnlp = options.getJNLP(); + jnlpd = getJNLPD(jnlp); + + // Check for required options in case of FX + if (jnlpd.isFXApp()) { + if (!options.isRuntimeImageSet()) { + throw new Exception("This is a JavaFX Web-Start application which requires a runtime image capable of running JavaFX applications, which can be specified by the jpackager option --runtime-image (using --jpackager-options)."); + } + } + + // Check href. It can be same as URL we provided or new one + // if JNLP has different href or codebase. We assume that + // XMLFormat.parse() will handle any errors in href and codebase + // correctly. + String href = jnlpd.getHref(); + if (href != null && !href.equalsIgnoreCase(jnlp)) { + if (href.startsWith("file:")) { + URI hrefURI = new URI(href); + URI jnlpURI = new URI(jnlp); + + String hrefPath = hrefURI.getPath(); + String jnlpPath = jnlpURI.getPath(); + + if (!hrefPath.equalsIgnoreCase(jnlpPath)) { + jnlp = href; + jnlpd = getJNLPD(jnlp); + } + } else { + jnlp = href; + jnlpd = getJNLPD(jnlp); + } + } + + if (jnlpd.getName() == null) { + jnlpd.setName(getNameFromURL(jnlp)); + } + } + + private static String getNameFromURL(String url) throws IOException { + int index; + int index1 = url.lastIndexOf('/'); + int index2 = url.lastIndexOf('\\'); + + if (index1 >= index2) { + index = index1; + } else { + index = index2; + } + + if (index != -1) { + String name = url.substring(index + 1, url.length()); + if (name.endsWith(".jnlp")) { + return name.substring(0, name.length() - 5); + } + } + + return null; + } + + private URL getCodeBase(String jnlp) throws Exception { + int index = jnlp.lastIndexOf('/'); + if (index != -1) { + if (HTTPHelper.isHTTPUrl(jnlp)) { + return new URL(jnlp.substring(0, index + 1)); + } else { + String codeBasePath = jnlp.substring(0, index); + if (!codeBasePath.endsWith("/")) { + codeBasePath += "/"; + } + return new URI(codeBasePath).toURL(); + } + } + + return null; + } + + public static void markFileToDelete(String file) { + if (file == null || file.isEmpty()) { + return; + } + + if (markFileToDelete) { + try { + File f = new File(file); + f.deleteOnExit(); + } catch (Exception e) { + // Print exception, but do not fail conversion. + Log.warning(e.getLocalizedMessage()); + } + } + } + + public static void deleteFile(String file) { + try { + File f = new File(file); + f.delete(); + } catch (Exception e) { + Log.warning(e.getLocalizedMessage()); + } + } + + private void downloadResources() throws Exception { + List jars = jnlpd.getResources(); + for (JARDesc jar : jars) { + if (jar.getVersion() != null) { + if (!jnlpd.isVersionEnabled()) { + throw new Exception("Error: Version based download protocol is not supported without -Djnlp.versionEnabled=true."); + } + } + + String destFile = null; + if (HTTPHelper.isHTTPUrl(jar.getLocation().toString())) { + if (jar.getVersion() != null) { + try { + destFile = HTTPHelper.downloadFile(jar.getVersionLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); + } catch (HTTPHelperException ex) { + if (ex.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { + System.out.println("Error downloading versioned JAR from " + jar.getVersionLocation()); + System.out.println(ex.getMessage()); + System.out.println("Downloading " + jar.getLocation() + " instead."); + destFile = HTTPHelper.downloadFile(jar.getLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); + } else { + throw ex; + } + } + } else { + destFile = HTTPHelper.downloadFile(jar.getLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); + } + markFileToDelete(destFile); + } else { + if (jar.getVersion() != null) { + try { + destFile = HTTPHelper.copyFile(jar.getVersionLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); + } catch (FileNotFoundException ex) { + System.out.println("Error copying versioned JAR from " + jar.getVersionLocation()); + System.out.println(ex.getMessage()); + System.out.println("Copying " + jar.getLocation() + " instead."); + destFile = HTTPHelper.copyFile(jar.getLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); + } + } else { + destFile = HTTPHelper.copyFile(jar.getLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); + } + markFileToDelete(destFile); + } + + if (jar.isNativeLib()) { + unpackNativeLib(destFile); + deleteFile(destFile); + } else { + jnlpd.addFile(jar.getName()); + } + } + + IconDesc icon = jnlpd.getIcon(); + if (icon != null) { + String destFile; + + if (HTTPHelper.isHTTPUrl(icon.getLocation())) { + destFile = HTTPHelper.downloadFile(icon.getLocation(), getIconDownloadFolder(), HTTPHelper.getFileNameFromURL(icon.getLocation())); + } else { + destFile = HTTPHelper.copyFile(icon.getLocation(), getIconDownloadFolder(), HTTPHelper.getFileNameFromURL(icon.getLocation())); + } + + markFileToDelete(destFile); + icon.setLocalLocation(destFile); + } + + AssociationDesc [] associations = jnlpd.getAssociations(); + if (associations != null) { + for (AssociationDesc association : associations) { + if (association.getIconUrl() != null) { + String destFile; + if (HTTPHelper.isHTTPUrl(association.getIconUrl())) { + destFile = HTTPHelper.downloadFile(association.getIconUrl(), getIconDownloadFolder(), HTTPHelper.getFileNameFromURL(association.getIconUrl())); + } else { + destFile = HTTPHelper.copyFile(association.getIconUrl(), getIconDownloadFolder(), HTTPHelper.getFileNameFromURL(association.getIconUrl())); + } + + markFileToDelete(destFile); + association.setIconLocalLocation(destFile); + } + } + } + } + + public void unpackNativeLib(String file) throws IOException { + try (JarFile jarFile = new JarFile(file)) { + Enumeration entries = jarFile.entries(); + + while (entries.hasMoreElements()) { + JarEntry entry = (JarEntry) entries.nextElement(); + + // Skip directories + if (entry.isDirectory()) { + continue; + } + + String entryName = entry.getName(); + // Skip anything in sub-directories + if (entryName.contains("\\") || entryName.contains("/")) { + continue; + } + + // Skip anything not ending with .dll, .dylib or .so + if (!entryName.endsWith(".dll") && !entryName.endsWith(".dylib") && !entryName.endsWith(".so")) { + continue; + } + + File destFile = new File(getJarDownloadFolder(), entryName); + if (destFile.exists()) { + Log.warning(destFile.getAbsolutePath() + " already exist and will not be overwriten by native library from " + file + "."); + continue; + } + + InputStream inputStream = jarFile.getInputStream(entry); + FileOutputStream outputStream = new FileOutputStream(destFile); + + byte[] buffer = new byte[HTTPHelper.BUFFER_SIZE]; + int length; + do { + length = inputStream.read(buffer); + if (length > 0) { + outputStream.write(buffer, 0, length); + } + } while (length > 0); + + jnlpd.addFile(entryName); + } + } + } + + private void validate() { + if (jnlpd.getMainJar() == null) { + Log.error("Cannot find main jar"); + } + + if (jnlpd.getMainClass() == null) { + Log.error("Cannot find main class"); + } + } + + private void addLaunchArg(String arg, List launchArgs) { + if (arg != null && !arg.isEmpty()) { + if (!options.isOptionPresent(arg)){ + launchArgs.add(arg); + } else { + Log.info(arg + " generated by JNLPConverter is dropped, since it is overwriten via --jpackager-options"); + } + } + } + + private void addLaunchArg(String arg, String value, List launchArgs) { + if (arg != null && !arg.isEmpty() && value != null && !value.isEmpty()) { + if (!options.isOptionPresent(arg)){ + launchArgs.add(arg); + launchArgs.add(value); + } else { + Log.info(arg + "=" + value +" generated by JNLPConverter is dropped, since it is overwriten via --jpackager-options"); + } + } + } + + private void displayLaunchArgs() { + if (Log.isVerbose()) { + System.out.println(); + System.out.println("jpackager launch arguments (each argument starts on new line):"); + launchArgs.forEach((arg) -> { + System.out.println(arg); + }); + } + } + + private static int fileAssociationsCount = 0; + private String getFileAssociationsFile() { + String file = getPropDownloadFolder(); + file += File.separator; + file += "fileAssociation"; + file += String.valueOf(fileAssociationsCount); + file += ".properties"; + + fileAssociationsCount++; + + return file; + } + + private void buildLaunchArgs() { + if (options.createImage()) { + addLaunchArg("create-image", launchArgs); + } else if (options.createInstaller()) { + if (options.getInstallerType() == null) { + addLaunchArg("create-installer", launchArgs); + } else { + addLaunchArg("create-installer", options.getInstallerType(), launchArgs); + } + } + + // Set verbose for jpackager if it is set for us. + if (options.verbose()) { + addLaunchArg("--verbose", launchArgs); + } + + addLaunchArg("--input", getJarDownloadFolder(), launchArgs); + addLaunchArg("--output", options.getOutput(), launchArgs); + addLaunchArg("--name", jnlpd.getName(), launchArgs); + addLaunchArg("--version", jnlpd.getVersion(), launchArgs); + addLaunchArg("--vendor", jnlpd.getVendor(), launchArgs); + addLaunchArg("--description", jnlpd.getDescription(), launchArgs); + addLaunchArg("--icon", jnlpd.getIconLocation(), launchArgs); + addLaunchArg("--main-jar", jnlpd.getMainJar(), launchArgs); + addLaunchArg("--class", jnlpd.getMainClass(), launchArgs); + + addFiles(launchArgs); + addArguments(launchArgs); + addJVMArgs(launchArgs); + + if (jnlpd.isDesktopHint()) { + if (Platform.isWindows()) { + addLaunchArg("--win-shortcut", launchArgs); + } else { + Log.warning("Ignoring shortcut hint, since it is not supported on current platform."); + } + } + + if (jnlpd.isMenuHint()) { + if (Platform.isWindows()) { + addLaunchArg("--win-menu", launchArgs); + addLaunchArg("--win-menu-group", jnlpd.getSubMenu(), launchArgs); + } else { + Log.warning("Ignoring menu hint, since it is not supported on current platform."); + } + } + + AssociationDesc [] associations = jnlpd.getAssociations(); + if (associations != null) { + for (AssociationDesc association : associations) { + String file = getFileAssociationsFile(); + markFileToDelete(file); + + try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)))) { + if (association.getExtensions() != null && association.getMimeType() != null) { + out.println(FA_EXTENSIONS + "=" + quote(association.getExtensions())); + out.println(FA_CONTENT_TYPE + "=" + quote(association.getMimeType())); + + if (association.getMimeDescription() != null) { + out.println(FA_DESCRIPTION + "=" + association.getMimeDescription()); + } + + if (association.getIconLocalLocation() != null) { + out.println(FA_ICON + "=" + quote(association.getIconLocalLocation())); + } + + addLaunchArg("--file-associations", file, launchArgs); + } + } catch (Exception ex) { + Log.warning(ex.toString()); + if (association.getExtensions() != null) { + Log.warning("File assoication for " + association.getExtensions() + " will be ignored due to exception above."); + } + } + } + } + + // Add options from --jpackager-options + List jpackagerOptions = options.getJPackagerOptions(); + jpackagerOptions.forEach((option) -> { + launchArgs.add(option); + }); + + displayLaunchArgs(); + } + + private String getCommandFileName() { + Platform platform = Platform.getPlatform(); + switch (platform) { + case WINDOWS: + return "run_jpackager.bat"; + case LINUX: + return "run_jpackager.sh"; + case MAC: + return "run_jpackager.sh"; + default: + Log.error("Cannot determine platform type."); + return ""; + } + } + + private void saveLaunchArgs() { + if (options.keep() != null) { + File keepFolder = new File(options.keep()); + String cmdFile = keepFolder.getAbsolutePath() + File.separator + getCommandFileName(); + try (PrintWriter out = new PrintWriter(cmdFile)) { + out.print(getJPackagerPath()); + launchArgs.forEach((arg) -> { + out.print(" "); + + if (arg.contains(" ")) { + int len = arg.length(); + if (len >= 1) { + if (arg.charAt(0) != '"' && arg.charAt(len - 1) != '"') { + out.print("\"" + arg + "\""); + } else { + if (Platform.isWindows()) { + out.print(arg); + } else { + arg = escapeQuote(arg); + out.print("\"" + arg + "\""); + } + } + } + } else { + out.print(arg); + } + }); + } catch (FileNotFoundException ex) { + Log.error("Cannot save file with command line: " + ex.getLocalizedMessage()); + } + } + } + + private void runJPackager() { + List command = new ArrayList<>(); + command.add(getJPackagerPath()); + command.addAll(launchArgs); + + ProcessBuilder builder = new ProcessBuilder(); + builder.inheritIO(); + builder.command(command); + + try { + Process process = builder.start(); + int exitCode = process.waitFor(); + if (exitCode != 0) { + Log.warning("jpackager retrun non zero code: " + exitCode); + } + } catch (IOException | InterruptedException ex) { + Log.error(ex.getMessage()); + } + } + + private void addFileList(String arg, List filesToAdd, List launchArgs) { + if (filesToAdd.isEmpty()) { + return; + } + + String filesArg = ""; + for (int i = 0; i < filesToAdd.size(); i++) { + filesArg += quote(filesToAdd.get(i)); + if ((i + 1) != filesToAdd.size()) { + filesArg += File.pathSeparator; + } + } + + launchArgs.add(arg); + launchArgs.add(filesArg); + } + + private void addFiles(List launchArgs) { + addFileList("--files", jnlpd.getFiles(), launchArgs); + } + + private void addArguments(List launchArgs) { + List arguments = jnlpd.getArguments(); + if (arguments.isEmpty()) { + return; + } + + String argsStr = ""; + for (int i = 0; i < arguments.size(); i++) { + String arg = arguments.get(i); + argsStr += quote(arg); + if ((i + 1) != arguments.size()) { + argsStr += " "; + } + } + + launchArgs.add("--arguments"); + if (Platform.isWindows()) { + if (argsStr.contains(" ")) { + if (argsStr.contains("\"")) { + argsStr = escapeQuote(argsStr); + } + argsStr = "\"" + argsStr + "\""; + } + } + launchArgs.add(argsStr); + } + + private void addJVMArgs(List launchArgs) { + List jvmArgs = jnlpd.getVMArgs(); + if (jvmArgs.isEmpty()) { + return; + } + + String jvmArgsStr = ""; + for (int i = 0; i < jvmArgs.size(); i++) { + String arg = jvmArgs.get(i); + jvmArgsStr += quote(arg); + if ((i + 1) != jvmArgs.size()) { + jvmArgsStr += " "; + } + } + + launchArgs.add("--jvm-args"); + if (Platform.isWindows()) { + if (jvmArgsStr.contains(" ")) { + if (jvmArgsStr.contains("\"")) { + jvmArgsStr = escapeQuote(jvmArgsStr); + } + jvmArgsStr = "\"" + jvmArgsStr + "\""; + } + } + launchArgs.add(jvmArgsStr); + } + + private String quote(String in) { + if (in == null) { + return null; + } + + if (in.isEmpty()) { + return ""; + } + + if (!in.contains("=")) { + // Not a property + if (in.contains(" ")) { + in = escapeQuote(in); + return "\"" + in + "\""; + } + return in; + } + + if (!in.contains(" ")) { + return in; // No need to quote + } + + int paramIndex = in.indexOf("="); + if (paramIndex <= 0) { + return in; // Something wrong, just skip quoting + } + + String param = in.substring(0, paramIndex); + String value = in.substring(paramIndex + 1); + + if (value.length() == 0) { + return in; // No need to quote + } + + value = escapeQuote(value); + + return param + "=" + "\"" + value + "\""; + } + + private String escapeQuote(String in) { + if (in == null) { + return null; + } + + if (in.isEmpty()) { + return ""; + } + + if (in.contains("\"")) { + // Use code points to preserve non-ASCII chars + StringBuilder sb = new StringBuilder(); + int codeLen = in.codePointCount(0, in.length()); + for (int i = 0; i < codeLen; i++) { + int code = in.codePointAt(i); + // Note: No need to escape '\' on Linux or OS X. + // jpackager expects us to pass arguments and properties with quotes and spaces as a map + // with quotes being escaped with additional \ for internal quotes. + // So if we want two properties below: + // -Djnlp.Prop1=Some "Value" 1 + // -Djnlp.Prop2=Some Value 2 + // jpackager will need: + // "-Djnlp.Prop1=\"Some \\"Value\\" 1\" -Djnlp.Prop2=\"Some Value 2\"" + // but since we using ProcessBuilder to run jpackager we will need to escape + // our escape symbols as well, so we will need to pass string below to ProcessBuilder: + // "-Djnlp.Prop1=\\\"Some \\\\\\\"Value\\\\\\\" 1\\\" -Djnlp.Prop2=\\\"Some Value 2\\\"" + switch (code) { + case '"': + // " -> \" -> \\\" + if (i == 0 || in.codePointAt(i - 1) != '\\') { + if (Platform.isWindows()) { + sb.appendCodePoint('\\'); + sb.appendCodePoint('\\'); + } + sb.appendCodePoint('\\'); + sb.appendCodePoint(code); + } + break; + case '\\': + // We need to escape already escaped symbols as well + if ((i + 1) < codeLen) { + int nextCode = in.codePointAt(i + 1); + if (nextCode == '"') { + // \" -> \\\" + sb.appendCodePoint('\\'); + sb.appendCodePoint('\\'); + sb.appendCodePoint('\\'); + sb.appendCodePoint(nextCode); + } else { + sb.appendCodePoint('\\'); + sb.appendCodePoint(code); + } + } else { + if (Platform.isWindows()) { + sb.appendCodePoint('\\'); + } + sb.appendCodePoint(code); + } + break; + default: + sb.appendCodePoint(code); + break; + } + } + return sb.toString(); + } + + return in; + } + + public synchronized String getDownloadFolder() { + if (downloadFolder == null) { + try { + File file; + if (options.keep() == null) { + Path path = Files.createTempDirectory("JNLPConverter"); + file = path.toFile(); + file.deleteOnExit(); + } else { + file = new File(options.keep()); + if (!file.exists()) { + file.mkdir(); + } + } + + downloadFolder = file.getAbsolutePath(); + } catch (IOException e) { + Log.error(e.getLocalizedMessage()); + } + } + + return downloadFolder; + } + + public final synchronized String getJnlpDownloadFolder() { + if (jnlpDownloadFolder == null) { + File file = new File(getDownloadFolder() + File.separator + "jnlp"); + file.mkdir(); + markFileToDelete(getDownloadFolder() + File.separator + "jnlp"); + jnlpDownloadFolder = file.getAbsolutePath(); + } + + return jnlpDownloadFolder; + } + + public static String getJnlpDownloadFolderStatic() { + return jnlpDownloadFolderStatic; + } + + public synchronized String getJarDownloadFolder() { + if (jarDownloadFolder == null) { + File file = new File(getDownloadFolder() + File.separator + "jar"); + file.mkdir(); + markFileToDelete(getDownloadFolder() + File.separator + "jar"); + jarDownloadFolder = file.getAbsolutePath(); + } + + return jarDownloadFolder; + } + + public synchronized String getIconDownloadFolder() { + if (iconDownloadFolder == null) { + File file = new File(getDownloadFolder() + File.separator + "icon"); + file.mkdir(); + markFileToDelete(getDownloadFolder() + File.separator + "icon"); + iconDownloadFolder = file.getAbsolutePath(); + } + + return iconDownloadFolder; + } + + public synchronized String getPropDownloadFolder() { + if (propDownloadFolder == null) { + File file = new File(getDownloadFolder() + File.separator + "prop"); + file.mkdir(); + markFileToDelete(getDownloadFolder() + File.separator + "prop"); + propDownloadFolder = file.getAbsolutePath(); + } + + return propDownloadFolder; + } + + public synchronized static String getJPackagerPath() { + if (jpackagerPath == null) { + jpackagerPath = System.getProperty("java.home"); + jpackagerPath += File.separator; + jpackagerPath += "bin"; + jpackagerPath += File.separator; + + Platform platform = Platform.getPlatform(); + switch (platform) { + case WINDOWS: + jpackagerPath += "jpackager.exe"; + break; + case LINUX: + jpackagerPath += "jpackager"; + break; + case MAC: + jpackagerPath += "jpackager"; + break; + default: + Log.error("Cannot determine platform type."); + break; + } + + Log.verbose("jpackager: " + jpackagerPath); + } + + return jpackagerPath; + } + + public static String getIconFormat(String icon) { + // GIF, JPEG, ICO, or PNG + if (icon.toLowerCase().endsWith(".gif")) { + return "GIF"; + } else if (icon.toLowerCase().endsWith(".jpg")) { + return "JPEG"; + } else if (icon.toLowerCase().endsWith(".ico")) { + return "ICO"; + } else if (icon.toLowerCase().endsWith(".png")) { + return "PNG"; + } + + return "UNKNOWN"; + } + + public static boolean isIconSupported(String icon) { + Platform platform = Platform.getPlatform(); + switch (platform) { + case WINDOWS: + if (icon.endsWith(".ico")) { + return true; + } else { + Log.warning("Icon file format (" + getIconFormat(icon) + ") is not supported on Windows for file " + icon + "."); + return false; + } + case LINUX: + if (icon.endsWith(".png")) { + return true; + } else { + Log.warning("Icon file format (" + getIconFormat(icon) + ") is not supported on Linux for file " + icon + "."); + return false; + } + case MAC: + Log.warning("Icon file format (" + getIconFormat(icon) + ") is not supported on OS X for file " + icon + "."); + return false; + } + + return false; + } +}