--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jpackager/JNLPConverter/src/jnlp/converter/JNLPConverter.java Fri Oct 12 19:00:51 2018 -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<String> 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<JARDesc> 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<String> 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<String> 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<String> 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<String> 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<String> filesToAdd, List<String> 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<String> launchArgs) {
+ addFileList("--files", jnlpd.getFiles(), launchArgs);
+ }
+
+ private void addArguments(List<String> launchArgs) {
+ List<String> 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<String> launchArgs) {
+ List<String> 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;
+ }
+}