diff --git a/src/java/org/lwjgl/applet/LWJGLInstaller.java b/src/java/org/lwjgl/applet/LWJGLInstaller.java
new file mode 100644
index 00000000..07328af2
--- /dev/null
+++ b/src/java/org/lwjgl/applet/LWJGLInstaller.java
@@ -0,0 +1,318 @@
+/*
+ * 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.applet;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.LWJGLUtil;
+
+/**
+ *
+ *
+ *
+ * @author Brian Matzon
+ * @version $Revision$
+ * $Id$
+ */
+public class LWJGLInstaller {
+
+ /**
+ * Files to install for each supported platform
+ * @see org.lwjgl.LWJGLUtil#getPlatform()
+ */
+ public static final String[][] PLATFORM_FILES = {
+ { "lwjgl", "lwjgl-fmod3", "lwjgl-devil", "openal", "fmod", "IL", "ILU", "ILUT", "jinput-osx"},
+ { "lwjgl", "lwjgl-fmod3", "lwjgl-devil", "openal", "fmod", "IL", "ILU", "ILUT", "jinput-linux"},
+ { "lwjgl", "lwjgl-fmod3", "lwjgl-devil", "OpenAL32", "fmod", "DevIL", "ILU", "ILUT", "jinput-dx8", "jinput-raw"}
+ };
+
+ /** Whether the installer has been called */
+ public static boolean installed;
+
+ /** Whether to hook uninstall rutine. Must be called prior to installation */
+ public static boolean disableUninstall = false;
+
+ /** Directory that was installed into */
+ public static String installDirectory;
+
+ /** Buffer used when copying files */
+ private static final byte[] COPY_BUFFER = new byte[4096];
+
+ private LWJGLInstaller() {
+ /* Unused */
+ }
+
+ /**
+ * Create a temporary installation of LWJGL.
+ * This will extract the relevant native files (for the platform) into
+ * the users temp directory, and instruct the LWJGL subsystem to load its
+ * native files from there.
+ * The files required by the installer, are gotten from the classloader via its
+ * getResource command, and are assumed to in the path: /native//
+ * Any call to this method will also add a shutdown hook to the uninstall of the libraries
+ * Note: Due to the nature of native libraries, we cannot actually uninstall the currently
+ * loaded files, but rather the "last" installed. This means that the most recent install of LWJGL
+ * will always be present in the users temp dir.
+ *
+ * @see java.lang.ClassLoader#getResource(String)
+ * @return true if the installation was successfull
+ */
+ public static boolean tempInstall() throws LWJGLException {
+ // only need to install once
+ if (installed) {
+ return true;
+ }
+
+ // libraries to validate and install
+ String[] libraries = PLATFORM_FILES[LWJGLUtil.getPlatform() - 1];
+
+ // Validate the certificates of the native files
+ validateCertificates();
+
+ // install shutdown installer hook
+ if(!disableUninstall) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ public void run() {
+ LWJGLInstaller.uninstall();
+ }
+ });
+ return null;
+ }
+ });
+ }
+
+ // create a temporary dir for the native files
+ String user_temp_dir = getPriveledgedString("java.io.tmpdir");
+ String path = createTemporaryDir(user_temp_dir);
+ if(path == null) {
+ throw new LWJGLException("Failed creation of temporary directory in " + user_temp_dir);
+ }
+
+ // extract natives
+ for (int i = 0; i < libraries.length; i++) {
+ String library = System.mapLibraryName(libraries[i]);
+ if(!extract(library, path)) {
+ LWJGLUtil.log("Failed extract of " + library + " to " + path);
+ uninstall();
+ return false;
+ }
+ }
+
+ installDirectory = path;
+ return installed = true;
+ }
+
+ /**
+ * Validates the certificates of the native libraries.
+ * When installing native libraries, it is imperative that we also check the certficates.
+ * The reson for this, is that a user may inject a malicious jar to the classpath
+ * before the "real" LWJGL jar, containing native libraries with unwanted code.
+ * By forcing all the native libraries to have the same certificate as the signed
+ * installer, we can also be sure that the native libraries indeed are correct.
+ * @throws LWJGLException If we encounter a certificate mismatch
+ */
+ private static void validateCertificates() throws LWJGLException {
+ /* TODO */
+ }
+
+ /**
+ * Extracts a file in the classpath to a specified dir
+ *
+ * @param file File to extract
+ * @param path Path to extract to
+ * @return true if the file was extracted successdully
+ */
+ private static boolean extract(final String file, final String path) throws LWJGLException {
+ return (Boolean) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ // check for existing file, and get out
+ File out = new File(path + File.separator + file);
+ if (out.exists()) {
+ return false;
+ }
+
+ // create the new file and copy it to its destination
+ try {
+ out.createNewFile();
+ String in = "/native/" + LWJGLUtil.getPlatformName() + "/" + file;
+ OutputStream os = new BufferedOutputStream(new FileOutputStream(out));
+ InputStream is = new BufferedInputStream(getClass().getResourceAsStream(in));
+
+ // Sanity check
+ // ===========================================
+ if (os == null) {
+ LWJGLUtil.log("Unable to write to outputstream at " + out.getAbsolutePath());
+ return false;
+ }
+
+ if (is == null) {
+ LWJGLUtil.log("Unable to read classpath inputstream from " + in);
+ return false;
+ }
+ // -------------------------------------------
+
+ // copy the actual file
+ copyFile(is, os);
+ } catch (IOException ioe) {
+ LWJGLUtil.log("Exception while extracting " + file + ": " + ioe.getMessage());
+ return false;
+ }
+ return true;
+ }
+ });
+ }
+
+ /**
+ * Copies an inputstream to an outputstream
+ * @param is InputStream to read from
+ * @param os OutputStream to write to
+ * @throws IOException if the copy process fail in any way
+ */
+ static void copyFile(InputStream is, OutputStream os) throws IOException {
+ int len;
+ while ((len = is.read(COPY_BUFFER)) > 0) {
+ os.write(COPY_BUFFER, 0, len);
+ }
+ is.close();
+ os.close();
+ }
+
+ /**
+ * Creates the temporary dir to store lwjgl files in.
+ * The temporary dir will be created in the users temp dir and
+ * called 'lwjgl-' and appended System.currentTimeMillis(). A watermark file
+ * called '.lwjglinstaller' will also be created in the directory.
+ * @return Name of temp directory or null if directory creation failed
+ */
+ static String createTemporaryDir(final String user_temp_dir) {
+ return (String) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ // create the temp directory
+ File tempDir = new File(user_temp_dir + File.separator + "lwjgl-" + System.currentTimeMillis());
+ if(!tempDir.mkdir()) {
+ return null;
+ }
+
+ // add the watermark file
+ // TODO: Write some info to the file ?
+ try {
+ File watermark = new File(tempDir.getAbsolutePath() + File.separator + ".lwjglinstaller");
+ watermark.createNewFile();
+ } catch (IOException ioe) {
+ return null;
+ }
+ return tempDir.getAbsolutePath();
+ }
+ });
+ }
+
+
+ /**
+ * Gets a property as a privileged action.
+ */
+ private static String getPriveledgedString(final String property) {
+ return (String) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty(property);
+ }
+ });
+ }
+
+ /**
+ * Uninstalls any PREVIOUS installations
+ * We cannot uninstall the current installation, since the files are locked
+ * by the VM.
+ */
+ private static void uninstall() {
+ LWJGLUtil.log("running LWJGL uninstaller");
+
+ // locate all installer dirs and uninstall them
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ String temp = System.getProperty("java.io.tmpdir");
+ File tempDir = new File(temp);
+ File[] files = tempDir.listFiles(new FileFilter() {
+
+ /*
+ * @see java.io.FileFilter#accept(java.io.File)
+ */
+ public boolean accept(File pathname) {
+ return pathname.getAbsolutePath().indexOf("lwjgl") != -1 && isInstallDirectory(pathname);
+ }
+
+ /**
+ * Checks whether the specified directory is an install directory.
+ * This is done by checking for the watermark file
+ * @param directory Directory to check
+ * @return true if the directory is an install directory
+ */
+ private boolean isInstallDirectory(File directory) {
+ File installFile = new File(directory.getAbsolutePath() + File.separator + ".lwjglinstaller");
+ return installFile.exists();
+ }
+
+ });
+
+ // uninstall each of the dirs
+ for (int i = 0; i < files.length; i++) {
+ uninstall(files[i]);
+ }
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Uninstall LWJGL from a directory. This deletes all the files in the directory
+ * and deletes the directory too.
+ * @param file directory to uninstall LWJGL from
+ */
+ private static void uninstall(File file) {
+ File[] files = file.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ files[i].delete();
+ }
+ file.delete();
+ }
+}
\ No newline at end of file