From 48c91afd16ba1864cef9c62eb384aeb56de7fc02 Mon Sep 17 00:00:00 2001
From: Brian Matzon
Date: Sun, 10 Jun 2007 20:30:03 +0000
Subject: [PATCH] initial checking on AppletLoader
---
res/appletlogo.png | Bin 0 -> 5512 bytes
res/appletprogress.gif | Bin 0 -> 8872 bytes
.../lwjgl/test/applet/AppletLoaderTest.java | 75 ++
.../org/lwjgl/util/applet/AppletLoader.java | 907 ++++++++++++++++++
4 files changed, 982 insertions(+)
create mode 100644 res/appletlogo.png
create mode 100644 res/appletprogress.gif
create mode 100644 src/java/org/lwjgl/test/applet/AppletLoaderTest.java
create mode 100644 src/java/org/lwjgl/util/applet/AppletLoader.java
diff --git a/res/appletlogo.png b/res/appletlogo.png
new file mode 100644
index 0000000000000000000000000000000000000000..626e7b4e0dc9a19fd625635dc9fde67a20f205c4
GIT binary patch
literal 5512
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
KMNUMnLSTYg4)~4$
literal 0
HcmV?d00001
diff --git a/res/appletprogress.gif b/res/appletprogress.gif
new file mode 100644
index 0000000000000000000000000000000000000000..709157cf196d3fb7018fdc8881c5e0651c8ec949
GIT binary patch
literal 8872
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
NbJL`aG#47s`7gC~db9ul
literal 0
HcmV?d00001
diff --git a/src/java/org/lwjgl/test/applet/AppletLoaderTest.java b/src/java/org/lwjgl/test/applet/AppletLoaderTest.java
new file mode 100644
index 00000000..c270693e
--- /dev/null
+++ b/src/java/org/lwjgl/test/applet/AppletLoaderTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2006 LWJGL Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'LWJGL' nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.lwjgl.test.applet;
+
+import java.applet.Applet;
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+
+import org.lwjgl.opengl.AWTInputAdapter;
+
+public class AppletLoaderTest extends Applet {
+
+ Test test = null;
+
+ public void destroy() {
+ super.destroy();
+ System.out.println("*** destroy ***");
+ AWTInputAdapter.destroy();
+ }
+
+ public void start() {
+ super.start();
+ System.out.println("*** start ***");
+ }
+
+ public void stop() {
+ super.stop();
+ System.out.println("*** stop ***");
+ test.stop();
+ }
+
+ public void init() {
+ System.out.println("*** init ***");
+
+ setLayout(new BorderLayout());
+ try {
+ test = (Test) Class.forName(getParameter("test")).newInstance();
+ Canvas canvas = (Canvas) test;
+ canvas.setSize(getWidth(), getHeight());
+ add(canvas);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ test.start();
+ }
+}
diff --git a/src/java/org/lwjgl/util/applet/AppletLoader.java b/src/java/org/lwjgl/util/applet/AppletLoader.java
new file mode 100644
index 00000000..a813d76a
--- /dev/null
+++ b/src/java/org/lwjgl/util/applet/AppletLoader.java
@@ -0,0 +1,907 @@
+/*
+ * Copyright (c) 2002-2007 LWJGL Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'LWJGL' nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.lwjgl.util.applet;
+
+import java.applet.Applet;
+import java.applet.AppletStub;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLConnection;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.cert.Certificate;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ *
+ * The AppletLoader enables deployment of LWJGL to applets in an easy
+ * and polished way. The loader will display a configurable logo and progressbar
+ * while the relevant jars (generic and native) are downloaded from a specified source.
+ *
+ *
+ * The downloaded are extracted to the users temporary directory - and if enabled, cached for
+ * faster loading in future uses.
+ *
+ *
+ * The following applet parameters are required:
+ *
+ * - al_main - [String] Full package and class the applet to instantiate and display when loaded.
+ * - al_logo - [String Path of of the logo resource to paint while loading.
+ * - al_progressbar - [String] Path of the progressbar resource to paint on top of the logo, width clipped by percentage.
+ * - al_jars - [String] Comma seperated list of jars to download.
+ * - al_windows - [String] Jar containing native files for windows.
+ * - al_linux - [String] Jar containing native files for linux.
+ * - al_mac - [String] Jar containing native files for mac.
+ *
+ *
+ *
+ * Additionally the following parameters can be supplied to tweak the behaviour of the AppletLoader.
+ *
+ * - al_version - [int or float] Version of deployment. If this is specified, the jars will be cached and
+ * reused if the version matches. If version doesn't match all of the files are reloaded.
+ * - al_bgcolor - [String] Hex formated color to use as background. Default: ffffff.
+ * - al_fgcolor - [String] Hex formated color to use as foreground. Default: 000000.
+ * - al_errorcolor - [String] Hex formated color to use as foreground color on error. Default: ff0000.
+ * - al_debug - [boolean] Whether to enable debug mode. Default: false.
+ *
+ *
+ * @author kappaOne
+ * @author Brian Matzon
+ * @version $Revision$
+ * $Id$
+ */
+public class AppletLoader extends Applet implements Runnable, AppletStub {
+ /** initializing */
+ public static final int STATE_INIT = 1;
+
+ /** determining which packages that are required */
+ public static final int STATE_DETERMINING_PACKAGES = 2;
+
+ /** checking for already downloaded files */
+ public static final int STATE_CHECKING_CACHE = 3;
+
+ /** downloading packages */
+ public static final int STATE_DOWNLOADING = 4;
+
+ /** extracting packages */
+ public static final int STATE_EXTRACTING_PACKAGES = 5;
+
+ /** updating the classpath */
+ public static final int STATE_UPDATING_CLASSPATH = 6;
+
+ /** switching to real applet */
+ public static final int STATE_SWITCHING_APPLET = 7;
+
+ /** initializing real applet */
+ public static final int STATE_INITIALIZE_REAL_APPLET = 8;
+
+ /** stating real applet */
+ public static final int STATE_START_REAL_APPLET = 9;
+
+ /** done */
+ public static final int STATE_DONE = 10;
+
+ /** used to calculate length of progress bar */
+ protected int percentage;
+
+ /** current size of download in bytes */
+ protected int currentSizeDownload;
+
+ /** total size of download in bytes */
+ protected int totalSizeDownload;
+
+ /** current size of extracted in bytes */
+ protected int currentSizeExtract;
+
+ /** total size of extracted in bytes */
+ protected int totalSizeExtract;
+
+ /** logo to be shown while loading */
+ protected Image logo;
+
+ /** progressbar to render while loading */
+ protected Image progressbar;
+
+ /** offscreen image used */
+ protected Image offscreen;
+
+ /** background color of applet */
+ protected Color bgColor = Color.white;
+
+ /** Color to write errors in */
+ protected Color errorColor = Color.red;
+
+ /** color to write forground in */
+ protected Color fgColor = Color.black;
+
+ /** urls of the jars to download */
+ protected URL[] urlList;
+
+ /** list of jars to download */
+ protected String jarList;
+
+ /** actual thread that does the loading */
+ protected Thread loaderThread;
+
+ /** animation thread that renders our loaderscreen while loading */
+ protected Thread animationThread;
+
+ /** applet to load after all downloads are complete */
+ protected Applet lwjglApplet;
+
+ /** whether a fatal error occured */
+ protected boolean fatalError;
+
+ /** fatal error that occured */
+ protected String fatalErrorDescription;
+
+ /** whether we're running in debug mode */
+ protected boolean debugMode;
+
+ /** String to display as a subtask */
+ protected String subtaskMessage = "";
+
+ /** state of applet loader */
+ protected int state = STATE_INIT;
+
+ /** generic error message to display on error */
+ protected String[] genericErrorMessage = { "An error occured while loading the applet.",
+ "Plese contact support to resolve this issue.",
+ ""};
+
+ /*
+ * @see java.applet.Applet#init()
+ */
+ public void init() {
+
+ // sanity check
+ String[] requiredArgs = {"al_main", "al_logo", "al_progressbar", "al_jars"};
+ for(int i=0; i 0) {
+ messageX = (getWidth() - fm.stringWidth(subtaskMessage)) / 2;
+ og.drawString(subtaskMessage, messageX, messageY+20);
+ }
+
+ // draw loading bar, clipping it depending on percentage done
+ int barSize = (progressbar.getWidth(this) * percentage) / 100;
+ og.clipRect(0, 0, x + barSize, getHeight());
+ og.drawImage(progressbar, x, y, null);
+ }
+
+ og.dispose();
+
+ // finally draw it all
+ g.drawImage(offscreen, 0, 0, null);
+ }
+
+ /**
+ * Reads list of jars to download and adds the urls to urlList
+ * also finds out which OS you are on and adds appropriate native
+ * jar to the urlList
+ */
+ protected void loadJarURLs() {
+ state = STATE_DETERMINING_PACKAGES;
+
+ StringTokenizer jar = new StringTokenizer(jarList, ", ");
+
+ int jarCount = jar.countTokens() + 1;
+
+ urlList = new URL[jarCount];
+
+ try {
+ URL path = getCodeBase();
+
+ // set jars urls
+ for (int i = 0; i < jarCount - 1; i++) {
+ urlList[i] = new URL(path, jar.nextToken());
+ }
+
+ // native jar url
+ String osName = System.getProperty("os.name");
+ String nativeJar = null;
+
+ if (osName.startsWith("Win")) {
+ nativeJar = getParameter("al_windows");
+ } else if (osName.startsWith("Linux") || osName.startsWith("FreeBSD") || osName.startsWith("SunOS")) {
+ nativeJar = getParameter("al_linux");
+ } else if (osName.startsWith("Mac")) {
+ nativeJar = getParameter("al_mac");
+ } else {
+ fatalErrorOccured("OS (" + osName + ") not supported");
+ }
+
+ if (nativeJar == null) {
+ fatalErrorOccured("no lwjgl natives files found");
+ } else {
+ urlList[jarCount - 1] = new URL(path, nativeJar);
+ }
+
+ } catch (MalformedURLException e) {
+ fatalErrorOccured(e.getMessage());
+ }
+ }
+
+ /**
+ * 4 steps
+ *
+ * 1) check version of applet and decide whether to download jars
+ * 2) download the jars
+ * 3) extract natives
+ * 4) add to jars to class path
+ * 5) switch applets
+ *
+ */
+ public void run() {
+
+ state = STATE_CHECKING_CACHE;
+
+ percentage = 5;
+
+ try {
+ if(debugMode) {
+ sleep(2000);
+ }
+
+ // get path where applet will be stored
+ String path = (String) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ return System.getProperty("java.io.tmpdir") + File.separator + getParameter("al_title") + File.separator;
+ }
+ });
+
+ File dir = new File(path);
+
+ // create directory
+ if (!dir.exists()) {
+ dir.mkdir();
+ }
+ dir = new File(dir, "version");
+
+ // if applet already available don't download anything
+ boolean cacheAvailable = false;
+
+ // version of applet
+ String version = getParameter("al_version");
+ float latestVersion = 0;
+
+ // if applet version specifed, check if you have latest version of applet
+ if (version != null) {
+
+ latestVersion = Float.parseFloat(version);
+
+ // if version file exists
+ if (dir.exists()) {
+ // compare to new version
+ if (latestVersion <= readVersionFile(dir)) {
+ cacheAvailable = true;
+ percentage = 90;
+ if(debugMode) {
+ sleep(2000);
+ }
+ }
+ }
+ }
+
+ // if jars not available or need updating download them
+ if (!cacheAvailable) {
+ // downloads jars from the server
+ downloadJars(path); // 10-65%
+
+ // Extracts Native Files
+ extractNatives(path); // 65-85%
+
+ // add version information once jars downloaded successfully
+ if (version != null) {
+ percentage = 90;
+ writeVersionFile(dir, latestVersion);
+ }
+ }
+
+ // add the downloaded jars and natives to classpath
+ updateClassPath(path);
+
+ // switch to LWJGL Applet
+ switchApplet();
+
+ state = STATE_DONE;
+ } catch (AccessControlException ace) {
+ fatalErrorOccured(ace.getMessage());
+ } catch (Exception e) {
+ fatalErrorOccured(e.getMessage());
+ } finally {
+ loaderThread = null;
+ }
+ }
+
+ /**
+ * read the current version file
+ *
+ * @param file the file to read
+ * @return the version value of saved file
+ * @throws Exception if it fails to read value
+ */
+ protected float readVersionFile(File file) throws Exception {
+ DataInputStream dis = new DataInputStream(new FileInputStream(file));
+ float version = dis.readFloat();
+ dis.close();
+ return version;
+ }
+
+ /**
+ * write out version file of applet
+ *
+ * @param file the file to write out to
+ * @param version the version of the applet as a float
+ * @throws Exception if it fails to write file
+ */
+ protected void writeVersionFile(File file, float version) throws Exception {
+ DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
+ dos.writeFloat(version);
+ dos.close();
+ }
+
+ /**
+ * Edits the ClassPath at runtime to include the jars
+ * that have just been downloaded and then adds the
+ * lwjgl natives folder property.
+ *
+ * @param path location where applet is stored
+ * @throws Exception if it fails to add classpath
+ */
+ protected void updateClassPath(String path) throws Exception {
+
+ state = STATE_UPDATING_CLASSPATH;
+
+ percentage = 95;
+
+ Class[] parameters = new Class[] { URL.class};
+
+ // modify class path by adding downloaded jars to it
+ for (int i = 0; i < urlList.length; i++) {
+ // get location of jar as a url
+ URL u = new URL("file:" + path + getFileName(urlList[i]));
+
+ // add to class path
+ Method method = URLClassLoader.class.getDeclaredMethod("addURL", parameters);
+ method.setAccessible(true);
+ method.invoke((URLClassLoader) ClassLoader.getSystemClassLoader(), new Object[] { u});
+ }
+
+ if(debugMode) {
+ sleep(2000);
+ }
+
+ // add natives files path to native class path
+ System.setProperty("org.lwjgl.librarypath", path + "natives");
+
+ // Make sure jinput knows about the new path too
+ System.setProperty("net.java.games.input.librarypath", path + "natives");
+
+ // replace security system to avoid bug where vm fails to
+ // recognise downloaded jars as signed, when they are
+ System.setSecurityManager(null);
+ }
+
+ /**
+ * replace the current applet with the lwjgl applet
+ * using AppletStub and initialise and start it
+ */
+ protected void switchApplet() throws Exception {
+
+ state = STATE_SWITCHING_APPLET;
+ percentage = 100;
+
+ if(debugMode) {
+ sleep(2000);
+ }
+
+ Class appletClass = Class.forName(getParameter("al_main"));
+ lwjglApplet = (Applet) appletClass.newInstance();
+
+ lwjglApplet.setStub(this);
+
+ setLayout(new GridLayout(1, 1));
+ add(lwjglApplet);
+ validate();
+
+ state = STATE_INITIALIZE_REAL_APPLET;
+ lwjglApplet.init();
+
+ state = STATE_START_REAL_APPLET;
+ lwjglApplet.start();
+ }
+
+ /**
+ * Will download the jars from the server using the list of urls
+ * in urlList, while at the same time updating progress bar
+ *
+ * @param path location of the directory to save to
+ * @throws Exception if download fails
+ */
+ protected void downloadJars(String path) throws Exception {
+
+ state = STATE_DOWNLOADING;
+
+ URLConnection urlconnection;
+
+ // calculate total size of jars to download
+ for (int i = 0; i < urlList.length; i++) {
+ urlconnection = urlList[i].openConnection();
+ totalSizeDownload += urlconnection.getContentLength();
+ }
+
+ int initialPercentage = percentage = 10;
+
+ // download each jar
+ byte buffer[] = new byte[65536];
+ for (int i = 0; i < urlList.length; i++) {
+ if(debugMode) {
+ sleep(2000);
+ }
+
+ urlconnection = urlList[i].openConnection();
+
+ String currentFile = getFileName(urlList[i]);
+ InputStream inputstream = urlconnection.getInputStream();
+ FileOutputStream fos = new FileOutputStream(path + currentFile);
+
+
+ int bufferSize;
+ while ((bufferSize = inputstream.read(buffer, 0, buffer.length)) != -1) {
+ if(debugMode) {
+ sleep(10);
+ }
+ fos.write(buffer, 0, bufferSize);
+ currentSizeDownload += bufferSize;
+ percentage = initialPercentage + ((currentSizeDownload * 55) / totalSizeDownload);
+ subtaskMessage = "Retrieving: " + currentFile + " " + ((currentSizeDownload * 100) / totalSizeDownload) + "%";
+ }
+ }
+ subtaskMessage = "";
+ }
+
+ /**
+ * This method will extract all file from the native jar and extract them
+ * to the subdirectory called "natives" in the local path, will also check
+ * to see if the native jar files is signed properly
+ *
+ * @param path base folder containing all downloaded jars
+ * @throws Exception if it fails to extract files
+ */
+ protected void extractNatives(String path) throws Exception {
+
+ state = STATE_EXTRACTING_PACKAGES;
+
+ int initialPercentage = percentage;
+
+ // get name of jar file with natives from urlList, it will be the last url
+ String nativeJar = getFileName(urlList[urlList.length - 1]);
+
+ // get the current certificate to compare against native files
+ Certificate[] certificate = AppletLoader.class.getProtectionDomain().getCodeSource().getCertificates();
+
+ // create native folder
+ File nativeFolder = new File(path + "natives");
+ if (!nativeFolder.exists()) {
+ nativeFolder.mkdir();
+ }
+
+ // open jar file
+ JarFile jarFile = new JarFile(path + nativeJar, true);
+
+ // get list of files in jar
+ Enumeration entities = jarFile.entries();
+
+ totalSizeExtract = 0;
+
+ // calculate the size of the files to extract for progress bar
+ while (entities.hasMoreElements()) {
+ JarEntry entry = (JarEntry) entities.nextElement();
+
+ // skip directories and anything in directories
+ // conveniently ignores the manifest
+ if (entry.isDirectory() || entry.getName().indexOf('/') != -1) {
+ continue;
+ }
+ totalSizeExtract += entry.getSize();
+ }
+
+ currentSizeExtract = 0;
+
+ // reset point to begining by getting list of file again
+ entities = jarFile.entries();
+
+ // extract all files from the jar
+ while (entities.hasMoreElements()) {
+ JarEntry entry = (JarEntry) entities.nextElement();
+
+ // skip directories and anything in directories
+ // conveniently ignores the manifest
+ if (entry.isDirectory() || entry.getName().indexOf('/') != -1) {
+ continue;
+ }
+
+ // check if native file already exists if so delete it to make room for new one
+ // useful when using the reload button on the browser
+ File f = new File(path + "natives" + File.separator + entry.getName());
+ if (f.exists()) {
+ if (!f.delete()) {
+ continue; // unable to delete file, it is in use, skip extracting it
+ }
+ }
+
+ if(debugMode) {
+ sleep(1000);
+ }
+
+ InputStream in = jarFile.getInputStream(jarFile.getEntry(entry.getName()));
+ OutputStream out = new FileOutputStream(path + "natives" + File.separator + entry.getName());
+
+ int bufferSize;
+ byte buffer[] = new byte[65536];
+
+ while ((bufferSize = in.read(buffer, 0, buffer.length)) != -1) {
+ if(debugMode) {
+ sleep(10);
+ }
+ out.write(buffer, 0, bufferSize);
+ currentSizeExtract += bufferSize;
+
+ // update progress bar
+ percentage = initialPercentage + ((currentSizeExtract * 20) / totalSizeExtract);
+ subtaskMessage = "Extracting: " + entry.getName() + " " + ((currentSizeExtract * 100) / totalSizeExtract) + "%";
+ }
+
+ // validate if the certificate for native file is correct
+ validateCertificateChain(certificate, entry.getCertificates());
+
+ in.close();
+ out.close();
+ }
+ subtaskMessage = "";
+
+ jarFile.close();
+ }
+
+ /**
+ * Validates the certificate chain for a single file
+ *
+ * @param ownCerts Chain of certificates to check against
+ * @param native_certs Chain of certificates to check
+ * @return true if the chains match
+ */
+ protected static void validateCertificateChain(Certificate[] ownCerts, Certificate[] native_certs) throws Exception {
+ if (native_certs == null)
+ throw new Exception("Unable to validate certificate chain. Native entry did not have a certificate chain at all");
+
+ if (ownCerts.length != native_certs.length)
+ throw new Exception("Unable to validate certificate chain. Chain differs in length [" + ownCerts.length + " vs " + native_certs.length + "]");
+
+ for (int i = 0; i < ownCerts.length; i++) {
+ if (!ownCerts[i].equals(native_certs[i])) {
+ throw new Exception("Certificate mismatch: " + ownCerts[i] + " != " + native_certs[i]);
+ }
+ }
+ }
+
+ /**
+ * Get Image from path provided
+ *
+ * @param s location of the image
+ * @return the Image file
+ */
+ protected Image getImage(String s) {
+ try {
+ DataInputStream datainputstream = new DataInputStream(getClass().getResourceAsStream(s));
+ byte abyte0[] = new byte[datainputstream.available()];
+ datainputstream.readFully(abyte0);
+ datainputstream.close();
+ return Toolkit.getDefaultToolkit().createImage(abyte0);
+ } catch (Exception e) {
+ /* */
+ }
+ return null;
+ }
+
+
+ /**
+ * Get file name portion of URL.
+ *
+ * @param url Get file name from this url
+ * @return file name as string
+ */
+ protected String getFileName(URL url) {
+ String fileName = url.getFile();
+ return fileName.substring(fileName.lastIndexOf('/') + 1);
+ }
+
+ /**
+ * Retrieves the color
+ *
+ * @param color Color to load
+ * @param defaultColor Default color to use if no color to load
+ * @return Color to use
+ */
+ protected Color getColor(String color, Color defaultColor) {
+ String param_color = getParameter(color);
+ if (param_color != null) {
+ return new Color(Integer.parseInt(param_color, 16));
+ }
+ return defaultColor;
+ }
+
+ /**
+ * Retrieves the boolean value for the applet
+ * @param name Name of parameter
+ * @param defaultValue default value to return if no such parameter
+ * @return value of parameter or defaultValue
+ */
+ protected boolean getBooleanParameter(String name, boolean defaultValue) {
+ String parameter = getParameter(name);
+ if(parameter != null) {
+ return Boolean.parseBoolean(parameter);
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Sets the state of the loaded and prints some debug information
+ *
+ * @param error Error message to print
+ * @param state State to enter
+ */
+ protected void fatalErrorOccured(String error) {
+ fatalError = true;
+ fatalErrorDescription = "Fatal error occured (" + state + "): " + error;
+ System.out.println(fatalErrorDescription);
+ repaint();
+ }
+
+ /**
+ * Utility method for sleeping
+ * @param ms milliseconds to sleep
+ */
+ protected void sleep(long ms) {
+ try {
+ Thread.sleep(ms);
+ } catch (Exception e) {
+ /* ignored */
+ }
+ }
+}
\ No newline at end of file