Added the game launcher JAR to downloaded files, remote ssh deploy, and removed old copy-paste of a JSON library

This commit is contained in:
Obique PSWG
2018-01-20 16:00:10 -06:00
parent e225834b21
commit ac2e8cb29a
13 changed files with 91 additions and 1292 deletions

18
.gitignore vendored
View File

@@ -1,5 +1,13 @@
/bin/
/build/
/.gradle/
/.settings/
/update/
.settings/
# IDE-based
*.iml
out/
.idea/
# Gradle
bin/
build/
.gradle/
gradle
gradlew*

View File

@@ -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'
}
}
}
}

View File

@@ -1 +1,2 @@
rootProject.name = 'LauncherUpdater'
include ':PSWGCommon', ':PSWGCommonFX'

View File

@@ -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();

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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<Object>, Iterable<Object> {
private final ArrayList<Object> array; // Specifically ArrayList for null value support
public JSONArray() {
array = new ArrayList<Object>();
}
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<? extends Object> c) {
ensureCapacity(size() + c.size());
for (Object o : c) {
add(o);
}
return true;
}
public boolean addAll(int index, Collection<? extends Object> 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<Object> subList(int fromIndex, int toIndex) {
return array.subList(fromIndex, toIndex);
}
public Object[] toArray() {
return array.toArray();
}
public <T> T[] toArray(T[] a) {
return array.toArray(a);
}
@Override
public ListIterator<Object> listIterator() {
return array.listIterator();
}
@Override
public ListIterator<Object> 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<Object> 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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<String, Object> {
private final Map<String, Object> attributes;
public JSONObject() {
attributes = new LinkedHashMap<String, Object>();
}
/**
* 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<? extends String, ? extends Object> m) {
for (Entry<? extends String, ? extends Object> e : m.entrySet()) {
put(e.getKey(), e.getValue());
}
}
public Object remove(Object key) {
return attributes.remove(key);
}
public Set<Entry<String, Object>> entrySet() {
return attributes.entrySet();
}
public Set<String> keySet() {
return attributes.keySet();
}
public Collection<Object> 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();
}
}

View File

@@ -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<String> 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();
}
}