diff --git a/.gitignore b/.gitignore index 66149c1..9098243 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,13 @@ -/bin/ -/build/ -/.gradle/ -/.settings/ -/update/ +.settings/ + +# IDE-based +*.iml +out/ +.idea/ + +# Gradle +bin/ +build/ +.gradle/ +gradle +gradlew* diff --git a/PSWGCommon b/PSWGCommon index 8505a99..bec3a8e 160000 --- a/PSWGCommon +++ b/PSWGCommon @@ -1 +1 @@ -Subproject commit 8505a996c3758d5b1d4054d302474d4cd6979808 +Subproject commit bec3a8e1e5661933fb202d1b6520da2b1df42759 diff --git a/PSWGCommonFX b/PSWGCommonFX index 32a8080..a12c894 160000 --- a/PSWGCommonFX +++ b/PSWGCommonFX @@ -1 +1 @@ -Subproject commit 32a80807c21f8bb779becc10ffe7bfd3fb94a4dd +Subproject commit a12c894c8723fff76ed19e4a1bd0e1990f06c351 diff --git a/build.gradle b/build.gradle index 2587c02..cb09954 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,19 @@ -apply plugin: 'application' -apply plugin: 'com.github.johnrengelman.shadow' -apply plugin: 'java' +buildscript { + repositories { + maven { url 'https://plugins.gradle.org/m2/' } + } + dependencies { + classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.0' + } +} + +plugins { + id 'com.github.johnrengelman.shadow' version '2.0.2' + id 'org.hidetake.ssh' version '2.9.0' + id 'application' + id 'java' + id 'idea' +} mainClassName = 'com.projectswg.installer.LauncherUpdater' @@ -11,26 +24,46 @@ manifest { sourceSets { main { java { - srcDirs = ['src'] - includes ['**/*.java'] + srcDir 'src' } } } shadowJar { - archiveName = "ProjectSWG.jar" + baseName = "ProjectSWG" + classifier = null + version = null +} + +repositories { + jcenter() } dependencies { compile project(':PSWGCommon') compile project(':PSWGCommonFX') + + compile group: "me.joshlarson", name: "fast-json", version: "2.2.3" } -buildscript { - repositories { - maven { url 'https://plugins.gradle.org/m2/' } - } - dependencies { - classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.0' +task wrapper(type: Wrapper) { + gradleVersion = "4.4" +} + +remotes { + server { + host = 'patch1.projectswg.com' + user = 'root' + identity = file("${System.properties['user.home']}/.ssh/id_rsa_pswg_patch") + } +} + +task deploy(dependsOn: shadowJar) { + doLast { + ssh.run { + session(remotes.server) { + put from: shadowJar.archivePath, into: '/var/www/patch1.projectswg.com/launcher_patch/ProjectSWG.jar' + } + } } } diff --git a/settings.gradle b/settings.gradle index f4d54cc..af61a6b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ +rootProject.name = 'LauncherUpdater' include ':PSWGCommon', ':PSWGCommonFX' diff --git a/src/com/projectswg/installer/LauncherUpdater.java b/src/com/projectswg/installer/LauncherUpdater.java index ae7307e..ca04f0d 100644 --- a/src/com/projectswg/installer/LauncherUpdater.java +++ b/src/com/projectswg/installer/LauncherUpdater.java @@ -18,10 +18,6 @@ */ package com.projectswg.installer; -import java.io.File; -import java.io.IOException; -import java.util.concurrent.atomic.AtomicBoolean; - import com.projectswg.common.concurrency.Delay; import com.projectswg.common.control.IntentManager; import com.projectswg.common.debug.Log; @@ -31,14 +27,16 @@ import com.projectswg.common.javafx.ResourceUtilities; import com.projectswg.common.process.JarProcessBuilder; import com.projectswg.common.process.JarProcessBuilder.MemoryUnit; import com.projectswg.common.utilities.LocalUtilities; - import javafx.application.Platform; +import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; + public class LauncherUpdater { private static final String LOCAL_JAR_FILE = "Launcher.jar"; - public static void main(String [] args) throws IOException { + public static void main(String [] args) { LocalUtilities.setApplicationName(".projectswg/launcher"); ResourceUtilities.setPrimarySource(LauncherUpdater.class); Log.addWrapper(new ConsoleLogWrapper(LogLevel.VERBOSE)); @@ -77,10 +75,9 @@ public class LauncherUpdater { private static boolean launch() { try { - File updaterDirectory = LocalUtilities.getSubApplicationDirectory("updater"); - File java = new File(System.getProperty("java.home"), "bin/java"); + File updaterDirectory = LocalUtilities.getApplicationDirectory(); File src = new File(updaterDirectory, LOCAL_JAR_FILE); - JarProcessBuilder builder = new JarProcessBuilder(java, src).setMemory(256, 256, MemoryUnit.MEGABYTES).inheritIO(); + JarProcessBuilder builder = new JarProcessBuilder(JarProcessBuilder.getJavaPath(), src).setMemory(256, 256, MemoryUnit.MEGABYTES).inheritIO(); Log.i("Launching jar... '%s'", src); Platform.runLater(LauncherUpdateGUI.getInstance()::close); builder.start().waitFor(); diff --git a/src/com/projectswg/installer/RemoteInstaller.java b/src/com/projectswg/installer/RemoteInstaller.java index 068f6ee..542c753 100644 --- a/src/com/projectswg/installer/RemoteInstaller.java +++ b/src/com/projectswg/installer/RemoteInstaller.java @@ -18,6 +18,14 @@ */ package com.projectswg.installer; +import com.projectswg.common.concurrency.Delay; +import com.projectswg.common.debug.Assert; +import com.projectswg.common.debug.Log; +import com.projectswg.common.javafx.ResourceUtilities; +import com.projectswg.common.utilities.LocalUtilities; +import me.joshlarson.json.JSON; +import me.joshlarson.json.JSONObject; + import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -27,19 +35,12 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import com.projectswg.common.concurrency.Delay; -import com.projectswg.common.debug.Assert; -import com.projectswg.common.debug.Log; -import com.projectswg.common.javafx.ResourceUtilities; -import com.projectswg.common.utilities.LocalUtilities; -import com.projectswg.installer.json.JSON; -import com.projectswg.installer.json.JSONObject; - public class RemoteInstaller { private static final String MANIFEST = "manifest.json"; private static final String INSTALLER = "ProjectSWG.jar"; private static final String LAUNCHER = "Launcher.jar"; + private static final String LAUNCHER_GAME = "GameLauncher.jar"; private static final String DATA = "data.zip"; private static final String REMOTE_URL = "patch1.projectswg.com"; @@ -47,6 +48,7 @@ public class RemoteInstaller { private static final String REMOTE_MANIFEST = REMOTE_PATH+'/'+MANIFEST; private static final String REMOTE_INSTALLER = REMOTE_PATH+'/'+INSTALLER; private static final String REMOTE_LAUNCHER = REMOTE_PATH+'/'+LAUNCHER; + private static final String REMOTE_LAUNCHER_GAME= REMOTE_PATH+'/'+LAUNCHER_GAME; private static final String REMOTE_DATA = REMOTE_PATH+'/'+DATA; private final InstallStatusCallback callback; @@ -59,7 +61,7 @@ public class RemoteInstaller { private RemoteInstaller(InstallStatusCallback callback) { this.callback = callback; - this.updateDirectory = LocalUtilities.getSubApplicationDirectory("updater"); + this.updateDirectory = LocalUtilities.getApplicationDirectory(); this.status = new AtomicReference<>(InstallStatus.CREATED); this.installerVersion = new AtomicReference<>(null); this.launcherVersion = new AtomicReference<>(null); @@ -92,7 +94,7 @@ public class RemoteInstaller { } } - private boolean testConnection() throws InstallerException { + private boolean testConnection() { verifyStatus(InstallStatus.INITIALIZED, InstallStatus.CONNECTED); try { RemoteUtilities.testConnection(REMOTE_URL, REMOTE_MANIFEST); @@ -153,10 +155,15 @@ public class RemoteInstaller { private void downloadLauncherUpdates() throws InstallerException { updateStatus(.2, "Starting launcher download..."); try { + double basePercent = 0.2; + double totalPercent = ((int) (0.8 / 3 * 100)) / 100.0; Log.d(" Downloading launcher..."); - RemoteUtilities.download(REMOTE_URL, REMOTE_LAUNCHER, new File(updateDirectory, LAUNCHER), (download, percent) -> updateStatus(.2+percent*0.35, "Downloading launcher patch...")); + download(REMOTE_LAUNCHER, new File(updateDirectory, LAUNCHER), basePercent, totalPercent, "Downloading launcher patch [core]..."); + basePercent += totalPercent; + download(REMOTE_LAUNCHER_GAME, new File(updateDirectory, LAUNCHER_GAME), basePercent, totalPercent, "Downloading launcher patch [game]..."); + basePercent += totalPercent; Log.d(" Downloading data..."); - RemoteUtilities.download(REMOTE_URL, REMOTE_DATA, new File(updateDirectory, DATA), (download, percent) -> updateStatus(.55+percent*0.35, "Downloading data patch...")); + download(REMOTE_DATA, new File(updateDirectory, DATA), basePercent, totalPercent, "Downloading data patch..."); } catch (IOException e) { Log.e(e); throw new InstallerException("downloading installer updates", e); @@ -212,7 +219,7 @@ public class RemoteInstaller { } } - private void completeInstallerDownload(AtomicBoolean running) throws InstallerException { + private void completeInstallerDownload(AtomicBoolean running) { Log.d(" Terminal operation. Waiting for user to restart launcher."); updateStatus(1, "Please restart the launcher to complete the update."); while (running.get()) { // Wait for user to restart the launcher @@ -229,6 +236,10 @@ public class RemoteInstaller { Assert.test(status.compareAndSet(oldStatus, newStatus), "Unable to update status! Expected: " + oldStatus); } + private void download(String remotePath, File local, double basePercent, double totalPercent, String status) throws IOException { + RemoteUtilities.download(REMOTE_URL, remotePath, local, (download, percent) -> updateStatus(basePercent+percent*totalPercent, status)); + } + /** * Safe function to reinstall the application. All failures are handled * @param callback the callback for progress updates diff --git a/src/com/projectswg/installer/json/JSON.java b/src/com/projectswg/installer/json/JSON.java deleted file mode 100644 index d45d69b..0000000 --- a/src/com/projectswg/installer/json/JSON.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.projectswg.installer.json; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; - -/** - * Provides convenience methods for stream operations that do automatic resource cleanup - */ -public class JSON { - - /** - * Opens a new JSONInputStream with the specified InputStream and reads a JSONObject. After - * reading, the input streams are closed - * - * @param is the input stream to read from - * @param printError TRUE if exception stack traces should be printed, FALSE otherwise - * @return the JSONObject read from the stream, or null if there was an exception - */ - public static JSONObject readObject(InputStream is, boolean printError) { - JSONInputStream in = new JSONInputStream(is); - try { - return in.readObject(); - } catch (IOException e) { - if (printError) - e.printStackTrace(); - } catch (JSONException e) { - if (printError) - e.printStackTrace(); - } finally { - try { - in.close(); - } catch (IOException e) { - if (printError) - e.printStackTrace(); - } - } - return null; - } - - /** - * Opens a new JSONInputStream with the specified string and reads a JSONObject - * - * @param str the string to read from - * @param printError TRUE if exception stack traces should be printed, FALSE otherwise - * @return the JSONObject read from the string, or null if there was an exception - */ - public static JSONObject readObject(String str, boolean printError) { - return readObject(new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8)), printError); - } - - /** - * Opens a new JSONInputStream with the specified InputStream and reads a JSONArray. After - * reading, the input streams are closed - * - * @param is the input stream to read from - * @param printError TRUE if exception stack traces should be printed, FALSE otherwise - * @return the JSONArray read from the stream, or null if there was an exception - */ - public static JSONArray readArray(InputStream is, boolean printError) { - JSONInputStream in = new JSONInputStream(is); - try { - return in.readArray(); - } catch (IOException e) { - if (printError) - e.printStackTrace(); - } catch (JSONException e) { - if (printError) - e.printStackTrace(); - } finally { - try { - in.close(); - } catch (IOException e) { - if (printError) - e.printStackTrace(); - } - } - return null; - } - - /** - * Opens a new JSONInputStream with the specified string and reads a JSONArray - * - * @param str the string to read from - * @param printError TRUE if exception stack traces should be printed, FALSE otherwise - * @return the JSONArray read from the string, or null if there was an exception - */ - public static JSONArray readArray(String str, boolean printError) { - return readArray(new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8)), printError); - } - -} diff --git a/src/com/projectswg/installer/json/JSONArray.java b/src/com/projectswg/installer/json/JSONArray.java deleted file mode 100644 index a2a8f63..0000000 --- a/src/com/projectswg/installer/json/JSONArray.java +++ /dev/null @@ -1,332 +0,0 @@ -package com.projectswg.installer.json; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; - -/** - * This class contains a list of values, which can be one of the following types: JSONObject, - * JSONArray, Number, Boolean, String, or null - */ -public class JSONArray implements List, Iterable { - - private final ArrayList array; // Specifically ArrayList for null value support - - public JSONArray() { - array = new ArrayList(); - } - - public int size() { - return array.size(); - } - - public void clear() { - array.clear(); - } - - public Object remove(int index) { - if (index < 0 || index >= array.size()) - throw new IndexOutOfBoundsException("Specified index " + index + " is out of range! [0, " + size() + ")"); - return array.remove(index); - } - - public void add(int index, Object o) { - if (o instanceof JSONObject || o instanceof JSONArray) - array.add(index, o); - else if (o instanceof Number || o instanceof Boolean) - array.add(index, o); - else if (o instanceof String) - array.add(index, o); - else if (o == null) - array.add(index, null); - else - throw new IllegalArgumentException("Object must be of type: JSONObject, JSONArray, Number, Boolean, String, or null!"); - } - - public boolean add(Object o) { - if (o instanceof JSONObject) - add((JSONObject) o); - else if (o instanceof JSONArray) - add((JSONArray) o); - else if (o instanceof Number) - add((Number) o); - else if (o instanceof Boolean) - add((Boolean) o); - else if (o instanceof String) - add((String) o); - else if (o == null) - addNull(); - else - throw new IllegalArgumentException("Object must be of type: JSONObject, JSONArray, Number, Boolean, String, or null!"); - return true; - } - - public boolean addAll(Collection c) { - ensureCapacity(size() + c.size()); - for (Object o : c) { - add(o); - } - return true; - } - - public boolean addAll(int index, Collection c) { - ensureCapacity(size() + c.size()); - int i = index; - for (Object o : c) { - add(i++, o); - } - return true; - } - - public boolean containsAll(Collection c) { - return array.containsAll(c); - } - - public void ensureCapacity(int minCapacity) { - array.ensureCapacity(minCapacity); - } - - public int indexOf(Object o) { - return array.indexOf(o); - } - - public boolean isEmpty() { - return array.isEmpty(); - } - - public int lastIndexOf(Object o) { - return array.lastIndexOf(o); - } - - public boolean remove(Object o) { - return array.remove(o); - } - - public boolean removeAll(Collection c) { - return array.removeAll(c); - } - - public boolean retainAll(Collection c) { - return array.retainAll(c); - } - - public Object set(int index, Object element) { - return array.set(index, element); - } - - public List subList(int fromIndex, int toIndex) { - return array.subList(fromIndex, toIndex); - } - - public Object[] toArray() { - return array.toArray(); - } - - public T[] toArray(T[] a) { - return array.toArray(a); - } - - @Override - public ListIterator listIterator() { - return array.listIterator(); - } - - @Override - public ListIterator listIterator(int index) { - return array.listIterator(index); - } - - /** - * Adds a JSONObject to the array - * - * @param obj the JSONObject to add - */ - public void add(JSONObject obj) { - array.add(obj); - } - - /** - * Adds a JSONArray to the array - * - * @param array the JSONArray to add - */ - public void add(JSONArray array) { - this.array.add(array); - } - - /** - * Adds a number to the array - * - * @param n the number to add - */ - public void add(Number n) { - array.add(n); - } - - /** - * Adds a boolean to the array - * - * @param b the boolean to add - */ - public void add(Boolean b) { - array.add(b); - } - - /** - * Adds a string to the array - * - * @param str the string to add - */ - public void add(String str) { - array.add(str); - } - - /** - * Adds a null value to the array - */ - public void addNull() { - array.add(null); - } - - /** - * Gets the object at the specified index from the array. The returned object will always be one - * of the supported JSON types: JSONObject, JSONArray, Number, Boolean, String, or null - * - * @param index the index to retrieve over the interval [0, size()) - * @return the object at the specified index - */ - public Object get(int index) { - return array.get(index); - } - - /** - * Gets the object at the specified index from the array. The returned object is casted to a - * JSONObject - * - * @param index the index to retrieve over the interval [0, size()) - * @return the object at the specified index - * @throws ClassCastException if the object is not a JSONObject - */ - public JSONObject getObject(int index) { - return (JSONObject) get(index); - } - - /** - * Gets the object at the specified index from the array. The returned object is casted to a - * JSONArray - * - * @param index the index to retrieve over the interval [0, size()) - * @return the array at the specified index - * @throws ClassCastException if the object is not a JSONArray - */ - public JSONArray getArray(int index) { - return (JSONArray) get(index); - } - - /** - * Gets the object at the specified index from the array. The returned object is casted to a int - * - * @param index the index to retrieve over the interval [0, size()) - * @return the int at the specified index - * @throws NullPointerException if the object is null - */ - public int getInt(int index) { - return ((Number) get(index)).intValue(); - } - - /** - * Gets the object at the specified index from the array. The returned object is casted to a - * long - * - * @param index the index to retrieve over the interval [0, size()) - * @return the long at the specified index - * @throws NullPointerException if the object is null - */ - public long getLong(int index) { - return ((Number) get(index)).longValue(); - } - - /** - * Gets the object at the specified index from the array. The returned object is casted to a - * float - * - * @param index the index to retrieve over the interval [0, size()) - * @return the float at the specified index - * @throws NullPointerException if the object is null - */ - public float getFloat(int index) { - return ((Number) get(index)).floatValue(); - } - - /** - * Gets the object at the specified index from the array. The returned object is casted to a - * double - * - * @param index the index to retrieve over the interval [0, size()) - * @return the double at the specified index - * @throws NullPointerException if the object is null - */ - public double getDouble(int index) { - return ((Number) get(index)).doubleValue(); - } - - /** - * Gets the object at the specified index from the array. The returned object is casted to a - * boolean - * - * @param index the index to retrieve over the interval [0, size()) - * @return the boolean at the specified index - * @throws NullPointerException if the object is null - * @throws ClassCastException if the object is not a boolean - */ - public boolean getBoolean(int index) { - return (boolean) get(index); - } - - /** - * Gets the object at the specified index from the array. The returned object is casted to a - * String - * - * @param index the index to retrieve over the interval [0, size()) - * @return the string at the specified index - * @throws ClassCastException if the object is not a String - */ - public String getString(int index) { - return (String) get(index); - } - - /** - * Determines whether or not the specified object exists inside this array - * - * @param o the object to search for within the array - * @return TRUE if the object exists, FALSE otherwise - */ - public boolean contains(Object o) { - return array.contains(o); - } - - @Override - public Iterator iterator() { - return array.iterator(); - } - - /** - * Returns a JSON string (RFC 4627) containing this array - * - * @return a JSON string compatible with RFC 4627 - */ - public String toString() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - new JSONOutputStream(baos).writeArray(this); - } catch (IOException e) { - return "Failed: " + e.getMessage(); - } - return baos.toString(); - } - -} diff --git a/src/com/projectswg/installer/json/JSONException.java b/src/com/projectswg/installer/json/JSONException.java deleted file mode 100644 index 6beb49d..0000000 --- a/src/com/projectswg/installer/json/JSONException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.projectswg.installer.json; - -public class JSONException extends Exception { - - private static final long serialVersionUID = 1L; - - public JSONException(String message) { - super(message); - } - -} diff --git a/src/com/projectswg/installer/json/JSONInputStream.java b/src/com/projectswg/installer/json/JSONInputStream.java deleted file mode 100644 index 2765271..0000000 --- a/src/com/projectswg/installer/json/JSONInputStream.java +++ /dev/null @@ -1,296 +0,0 @@ -package com.projectswg.installer.json; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; - -/** - * This input stream will read RFC 4627 compatible JSON strings from either a string or an input - * stream - */ -public class JSONInputStream extends InputStream { - - private final InputStream is; - private final byte[] buffer; - private int bufferPos; - private int bufferSize; - private char peek; - private boolean hasPeek; - private boolean previousTokenString; - - /** - * Creates a new input stream around the specified string - * - * @param str a RFC 4627 JSON string - */ - public JSONInputStream(String str) { - this(new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8))); - } - - /** - * Creates a new input stream around the specified input stream - * - * @param is the input stream pointing to the RFC 4627 JSON string - */ - public JSONInputStream(InputStream is) { - this.is = is; - this.buffer = new byte[256]; - this.bufferPos = 0; - this.bufferSize = 0; - this.peek = 0; - this.hasPeek = false; - this.previousTokenString = false; - } - - /** - * Reads a JSONObject from the stream - * - * @return the read JSONObject - * @throws IOException if there is an exception within the input stream - * @throws JSONException if there is a JSON parsing error - */ - public JSONObject readObject() throws IOException, JSONException { - readAssert(getNextToken().equals("{"), "JSONObject must start with '{'"); - return getNextObjectInternal(); - } - - /** - * Reads a JSONArray from the stream - * - * @return the read JSONArray - * @throws IOException if there is an exception within the input stream - * @throws JSONException if there is a JSON parsing error - */ - public JSONArray readArray() throws IOException, JSONException { - readAssert(getNextToken().equals("["), "JSONArray must start with '['"); - return getNextArrayInternal(); - } - - private JSONObject getNextObjectInternal() throws IOException, JSONException { - JSONObject obj = new JSONObject(); - String token = getNextToken(); - while (!token.equals("}")) { - String key = token; - readAssert(getNextToken().equals(":"), "Attributes must be key-value pairs separated by ':'"); - token = getNextToken(); - if (previousTokenString) - obj.put(key, token); - else if (token.equals("null")) - obj.putNull(key); - else if (token.equals("false")) - obj.put(key, false); - else if (token.equals("true")) - obj.put(key, true); - else if (token.equals("[")) - obj.put(key, getNextArrayInternal()); - else if (token.equals("{")) - obj.put(key, getNextObjectInternal()); - else { - try { - if (token.indexOf('.') != -1) - obj.put(key, Double.valueOf(token)); - else - obj.put(key, Long.valueOf(token)); - } catch (NumberFormatException e) { - e.printStackTrace(); - } - } - token = getNextToken(); - if (!token.equals("}")) { - readAssert(token.equals(","), "Attributes must be key-value pairs enumerated by ','"); - token = getNextToken(); - } - } - return obj; - } - - private JSONArray getNextArrayInternal() throws IOException, JSONException { - JSONArray array = new JSONArray(); - String token = getNextToken(); - while (!token.equals("]")) { - if (previousTokenString) - array.add(token); - else if (token.equals("null")) - array.addNull(); - else if (token.equals("false")) - array.add(false); - else if (token.equals("true")) - array.add(true); - else if (token.equals("[")) - array.add(getNextArrayInternal()); - else if (token.equals("{")) - array.add(getNextObjectInternal()); - else { - try { - if (token.indexOf('.') != -1) - array.add(Double.valueOf(token)); - else - array.add(Long.valueOf(token)); - } catch (NumberFormatException e) { - e.printStackTrace(); - } - } - token = getNextToken(); - if (!token.equals("]")) { - readAssert(token.equals(","), "Values must be enumerated by ','"); - token = getNextToken(); - } - } - return array; - } - - private String getNextToken() throws IOException, JSONException { - char c = ingestWhitespace(); - previousTokenString = false; - if (c == 0) - return ""; - if (c == '{' || c == '[' || c == '}' || c == ']' || c == ',' || c == ':') { - return Character.toString(c); - } - StringBuilder builder = new StringBuilder(); - if (c == '\"') { - getNextTokenString(builder); - previousTokenString = true; - } else { - builder.append(c); - getNextTokenOther(builder); - } - return builder.toString(); - } - - private void readAssert(boolean val, String message) throws JSONException { - if (!val) - throw new JSONException(message); - } - - private void getNextTokenString(StringBuilder builder) throws IOException, JSONException { - char c = readChar(); - boolean prevEscape = false; - while (c != '\"' || prevEscape) { - if (c != '\\' || prevEscape) - builder.append(c); - prevEscape = (c == '\\' && !prevEscape); - c = readChar(); - if (prevEscape) { - switch (c) { - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'b': - c = '\b'; - break; - case 'u': - c = (char) Integer.valueOf("" + readChar() + readChar() + readChar() + readChar(), 16).intValue(); - break; - case '\"': - case '\\': - break; - default: - throw new JSONException("Unknown escaped character: " + c); - } - } - } - } - - private void getNextTokenOther(StringBuilder builder) throws IOException { - while (isLetterOrNumber(peekChar())) { - builder.append(readChar()); - } - } - - private boolean isLetterOrNumber(char c) { - return isUppercase(c) || isLowercase(c) || isDigit(c) || isExtraNumCharacter(c); - } - - private boolean isUppercase(char c) { - return c >= 'A' && c <= 'Z'; - } - - private boolean isLowercase(char c) { - return c >= 'a' && c <= 'z'; - } - - private boolean isDigit(char c) { - return c >= '0' && c <= '9'; - } - - private boolean isExtraNumCharacter(char c) { - return c == '.' || c == '-' || c == 'E' || c == 'e' || c == '+'; - } - - private boolean isWhitespace(char c) { - return c == ' ' || c == '\n' || c == '\t' || c == '\r'; - } - - private char ingestWhitespace() throws IOException { - char c; - do { - c = readChar(); - } while (isWhitespace(c)); - return (char) c; - } - - public char peekChar() throws IOException { - if (hasPeek) - return peek; - peek = readChar(); - hasPeek = true; - return peek; - } - - public char readChar() throws IOException { - if (hasPeek) { - hasPeek = false; - return peek; - } - int r = read(); - if (r == -1) - return 0; - return (char) r; - } - - @Override - public int read() throws IOException { - if (bufferPos >= bufferSize) { - bufferSize = read(buffer, 0, Math.min(buffer.length, available())); - bufferPos = 0; - if (bufferSize < 0) - return -1; - if (bufferSize == 0) - return is.read(); - } - return buffer[bufferPos++]; - } - - public int read(byte[] b) throws IOException { - return is.read(b); - } - - public int read(byte[] b, int off, int len) throws IOException { - return is.read(b, off, len); - } - - public long skip(long n) throws IOException { - return is.skip(n); - } - - public int available() throws IOException { - return is.available(); - } - - public void close() throws IOException { - is.close(); - } - - public void reset() throws IOException { - is.reset(); - } - -} diff --git a/src/com/projectswg/installer/json/JSONObject.java b/src/com/projectswg/installer/json/JSONObject.java deleted file mode 100644 index 505f233..0000000 --- a/src/com/projectswg/installer/json/JSONObject.java +++ /dev/null @@ -1,317 +0,0 @@ -package com.projectswg.installer.json; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InvalidClassException; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -/** - * This class contains key-value pairs where the key is a string and the value is one of the - * following types: JSONObject, JSONArray, Number, Boolean, String, or null - */ -public class JSONObject implements Map { - - private final Map attributes; - - public JSONObject() { - attributes = new LinkedHashMap(); - } - - /** - * Returns the number of key-value pairs in the map - * - * @return the number of key-value pairs in the map - */ - public int size() { - return attributes.size(); - } - - /** - * Clears the internal map of all key-value pairs - */ - public void clear() { - attributes.clear(); - } - - /** - * Removes the key-value pair from the map - * - * @param key the key to remove - */ - public Object remove(String key) { - if (key == null) - throw new NullPointerException("Key cannot be null!"); - - return attributes.remove(key); - } - - public boolean containsKey(Object key) { - return attributes.containsKey(key); - } - - public boolean containsValue(Object value) { - return attributes.containsValue(value); - } - - public Object get(Object key) { - return attributes.get(key); - } - - public boolean isEmpty() { - return attributes.isEmpty(); - } - - public Object put(String key, Object value) { - if (value instanceof JSONObject || value instanceof JSONArray) - return attributes.put(key, value); - if (value instanceof Number || value instanceof Boolean) - return attributes.put(key, value); - if (value instanceof String) - return attributes.put(key, value); - if (value == null) - return attributes.put(key, null); - throw new IllegalArgumentException("Value must be of type: JSONObject, JSONArray, Number, Boolean, String, or null!"); - } - - public void putAll(Map m) { - for (Entry e : m.entrySet()) { - put(e.getKey(), e.getValue()); - } - } - - public Object remove(Object key) { - return attributes.remove(key); - } - - public Set> entrySet() { - return attributes.entrySet(); - } - - public Set keySet() { - return attributes.keySet(); - } - - public Collection values() { - return attributes.values(); - } - - public boolean equals(Object o) { - return attributes.equals(o); - } - - public int hashCode() { - return attributes.hashCode(); - } - - /** - * Puts a JSONObject into the map with the specified key - * - * @param key the key for the map - * @param value the value associated with the specified key - * @throws NullPointerException if the specified key is null - */ - public void put(String key, JSONObject value) { - if (key == null) - throw new NullPointerException("Key cannot be null!"); - - attributes.put(key, value); - } - - /** - * Puts a JSONArray into the map with the specified key - * - * @param key the key for the map - * @param value the value associated with the specified key - * @throws NullPointerException if the specified key is null - */ - public void put(String key, JSONArray value) { - if (key == null) - throw new NullPointerException("Key cannot be null!"); - - attributes.put(key, value); - } - - /** - * Puts a number into the map with the specified key - * - * @param key the key for the map - * @param value the value associated with the specified key - * @throws NullPointerException if the specified key is null - */ - public void put(String key, Number value) { - if (key == null) - throw new NullPointerException("Key cannot be null!"); - - attributes.put(key, value); - } - - /** - * Puts a boolean into the map with the specified key - * - * @param key the key for the map - * @param value the value associated with the specified key - * @throws NullPointerException if the specified key is null - */ - public void put(String key, Boolean value) { - if (key == null) - throw new NullPointerException("Key cannot be null!"); - - attributes.put(key, value); - } - - /** - * Puts a string into the map with the specified key - * - * @param key the key for the map - * @param value the value associated with the specified key - * @throws NullPointerException if the specified key is null - */ - public void put(String key, String value) { - if (key == null) - throw new NullPointerException("Key cannot be null!"); - - attributes.put(key, value); - } - - /** - * Puts a null value into the map with the specified key - * - * @param key the key for the map - * @param value the value associated with the specified key - * @throws NullPointerException if the specified key is null - */ - public void putNull(String key) { - if (key == null) - throw new NullPointerException("Key cannot be null!"); - - attributes.put(key, null); - } - - /** - * Gets the value associated with the specified key. The value will always be a supported JSON - * object: JSONObject, JSONArray, Number, Boolean, String, or null - * - * @param key the key for the map - * @return the value associated with the specified key - * @throws NullPointerException if the specified key is null - */ - public Object get(String key) { - if (key == null) - throw new NullPointerException("Key cannot be null!"); - - return attributes.get(key); - } - - /** - * Gets the value associated with the specified key. The value is casted to a JSONObject - * internally - * - * @param key the key for the map - * @return the JSONObject associated with the specified key - * @throws NullPointerException if the specified key is null - * @throws InvalidClassException if the object is not a JSONObject - */ - public JSONObject getObject(String key) { - return (JSONObject) get(key); - } - - /** - * Gets the value associated with the specified key. The value is casted to a JSONArray - * internally - * - * @param key the key for the map - * @return the JSONArray associated with the specified key - * @throws NullPointerException if the specified key is null - * @throws InvalidClassException if the object is not a JSONArray - */ - public JSONArray getArray(String key) { - return (JSONArray) get(key); - } - - /** - * Gets the value associated with the specified key. The value is casted to a int internally - * - * @param key the key for the map - * @return the int associated with the specified key - * @throws NullPointerException if the specified key is null or if the value is null - */ - public int getInt(String key) { - return ((Number) get(key)).intValue(); - } - - /** - * Gets the value associated with the specified key. The value is casted to a long internally - * - * @param key the key for the map - * @return the long associated with the specified key - * @throws NullPointerException if the specified key is null or if the value is null - */ - public long getLong(String key) { - return ((Number) get(key)).longValue(); - } - - /** - * Gets the value associated with the specified key. The value is casted to a float internally - * - * @param key the key for the map - * @return the float associated with the specified key - * @throws NullPointerException if the specified key is null or if the value is null - */ - public float getFloat(String key) { - return ((Number) get(key)).floatValue(); - } - - /** - * Gets the value associated with the specified key. The value is casted to a double internally - * - * @param key the key for the map - * @return the double associated with the specified key - * @throws NullPointerException if the specified key is null or if the value is null - */ - public double getDouble(String key) { - return ((Number) get(key)).doubleValue(); - } - - /** - * Gets the value associated with the specified key. The value is casted to a boolean internally - * - * @param key the key for the map - * @return the boolean associated with the specified key - * @throws NullPointerException if the specified key is null or if the value is null - * @throws InvalidClassException if the object is not a boolean - */ - public boolean getBoolean(String key) { - return (boolean) get(key); - } - - /** - * Gets the value associated with the specified key. The value is casted to a String internally - * - * @param key the key for the map - * @return the String associated with the specified key - * @throws NullPointerException if the specified key is null - * @throws InvalidClassException if the object is not a String - */ - public String getString(String key) { - return (String) get(key); - } - - /** - * Returns a JSON string (RFC 4627) containing this object - * - * @return a JSON string compatible with RFC 4627 - */ - public String toString() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - new JSONOutputStream(baos).writeObject(this); - } catch (IOException e) { - return "Failed: " + e.getMessage(); - } - return baos.toString(); - } - -} diff --git a/src/com/projectswg/installer/json/JSONOutputStream.java b/src/com/projectswg/installer/json/JSONOutputStream.java deleted file mode 100644 index c6effac..0000000 --- a/src/com/projectswg/installer/json/JSONOutputStream.java +++ /dev/null @@ -1,202 +0,0 @@ -package com.projectswg.installer.json; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.util.Set; - -/** - * This output stream will write RFC 4627 JSON strings out - */ -public class JSONOutputStream extends OutputStream { - - private final OutputStream os; - private String indentation; - private boolean compact; - - /** - * Wraps this JSON output stream around the specified output stream - * - * @param os the output stream to wrap - */ - public JSONOutputStream(OutputStream os) { - this.os = os; - this.indentation = " "; - this.compact = false; - } - - /** - * Sets the indentation for each additional tab. This is not used if compact is set to true - * - * @param indentation the indentation for each tab - * @see setCompact - */ - public void setIndentation(String indentation) { - this.indentation = indentation; - } - - /** - * Sets the mode to compact. If TRUE, there is no indentation or newlines - * - * @param compact TRUE to enable compact, FALSE otherwise - */ - public void setCompact(boolean compact) { - this.compact = compact; - } - - /** - * Writes the specified JSONObject to the output stream - * - * @param obj the JSONObject to write - * @throws IOException if there is an I/O error - */ - public void writeObject(JSONObject obj) throws IOException { - writeObject(obj, 0); - } - - /** - * Writes the specified JSONArray to the output stream - * - * @param array the JSONArray to write - * @throws IOException if there is an I/O error - */ - public void writeArray(JSONArray array) throws IOException { - writeArray(array, 0); - } - - private void writeObject(JSONObject obj, int depth) throws IOException { - write('{'); - if (!compact) - write('\n'); - int i = 0; - Set keys = obj.keySet(); - for (String key : keys) { - if (!compact) - writeIndentation(depth + 1); - writeStringSafe("\"" + escapeString(key) + "\": "); - writeValue(obj.get(key), depth + 1); - if (i + 1 < keys.size()) - write(','); - if (!compact) - write('\n'); - i++; - } - if (!compact) - writeIndentation(depth); - write('}'); - } - - private void writeArray(JSONArray array, int depth) throws IOException { - write('['); - if (!compact) - write('\n'); - for (int i = 0; i < array.size(); i++) { - if (!compact) - writeIndentation(depth + 1); - Object o = array.get(i); - writeValue(o, depth + 1); - if (i + 1 < array.size()) - write(','); - if (!compact) - write('\n'); - } - if (!compact) - writeIndentation(depth); - write(']'); - } - - private void writeValue(Object o, int depth) throws IOException { - if (o instanceof String) // String - writeStringSafe("\"" + escapeString((String) o) + "\""); - else if (o instanceof Number) // Number - writeNumber((Number) o); - else if (o instanceof Boolean) // Boolean - writeString(o.toString()); - else if (o == null) // Null - writeString("null"); - else if (o instanceof JSONObject) // Object - writeObject(((JSONObject) o), depth); - else if (o instanceof JSONArray) // Array - writeArray(((JSONArray) o), depth); - } - - private void writeNumber(Number n) throws IOException { - if (n instanceof Double && (Double.isNaN((Double) n) || Double.isInfinite((Double) n))) { - write('0'); - return; - } - if (n instanceof Float && (Float.isNaN((Float) n) || Float.isInfinite((Float) n))) { - write('0'); - return; - } - writeString(n.toString()); - } - - private void writeIndentation(int depth) throws IOException { - for (int i = 0; i < depth; ++i) - writeString(indentation); - } - - private void writeString(String str) throws IOException { - for (int i = 0; i < str.length(); ++i) - write(str.charAt(i)); - } - - private void writeStringSafe(String str) throws IOException { - write(str.getBytes(StandardCharsets.UTF_8)); - } - - private String escapeString(String str) { - StringBuilder builder = new StringBuilder(str.length()); - char c; - for (int i = 0; i < str.length(); ++i) { - c = str.charAt(i); - if (c == '\\' || c == '\"') { - builder.append('\\'); - builder.append(c); - } else if (c <= 0x1F) { - builder.append('\\'); - switch (c) { - case '\n': - builder.append('n'); - break; - case '\r': - builder.append('r'); - break; - case '\t': - builder.append('t'); - break; - case '\b': - builder.append('b'); - break; - default: - builder.append(String.format("u%04X", (int) c)); - break; - } - } else - builder.append(c); - } - return builder.toString(); - } - - public void write(int b) throws IOException { - os.write(b); - } - - public void write(byte[] b) throws IOException { - os.write(b); - } - - public void write(byte[] b, int off, int len) throws IOException { - os.write(b, off, len); - } - - public void flush() throws IOException { - os.flush(); - } - - public void close() throws IOException { - os.close(); - } - -}