First Commit. Final project complete.
This commit is contained in:
commit
c07375c979
6
.classpath
Normal file
6
.classpath
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/bin/
|
17
.project
Normal file
17
.project
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>sigIRCv2</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
11
.settings/org.eclipse.jdt.core.prefs
Normal file
11
.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,11 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
1
log_2_24_1.txt/log_2_24_1.txt
Normal file
1
log_2_24_1.txt/log_2_24_1.txt
Normal file
@ -0,0 +1 @@
|
||||
sigonitori: This will go in the log file!
|
284
src/org/json/CDL.java
Normal file
284
src/org/json/CDL.java
Normal file
@ -0,0 +1,284 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This provides static methods to convert comma delimited text into a
|
||||
* JSONArray, and to convert a JSONArray into comma delimited text. Comma
|
||||
* delimited text is a very popular format for data interchange. It is
|
||||
* understood by most database, spreadsheet, and organizer programs.
|
||||
* <p>
|
||||
* Each row of text represents a row in a table or a data record. Each row
|
||||
* ends with a NEWLINE character. Each row contains one or more values.
|
||||
* Values are separated by commas. A value can contain any character except
|
||||
* for comma, unless is is wrapped in single quotes or double quotes.
|
||||
* <p>
|
||||
* The first row usually contains the names of the columns.
|
||||
* <p>
|
||||
* A comma delimited list can be converted into a JSONArray of JSONObjects.
|
||||
* The names for the elements in the JSONObjects can be taken from the names
|
||||
* in the first row.
|
||||
* @author JSON.org
|
||||
* @version 2016-05-01
|
||||
*/
|
||||
public class CDL {
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be wrapped in quotes. The value can
|
||||
* be empty.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @return The value string, or null if empty.
|
||||
* @throws JSONException if the quoted string is badly formed.
|
||||
*/
|
||||
private static String getValue(JSONTokener x) throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
StringBuffer sb;
|
||||
do {
|
||||
c = x.next();
|
||||
} while (c == ' ' || c == '\t');
|
||||
switch (c) {
|
||||
case 0:
|
||||
return null;
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
sb = new StringBuffer();
|
||||
for (;;) {
|
||||
c = x.next();
|
||||
if (c == q) {
|
||||
//Handle escaped double-quote
|
||||
if(x.next() != '\"')
|
||||
{
|
||||
x.back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == 0 || c == '\n' || c == '\r') {
|
||||
throw x.syntaxError("Missing close quote '" + q + "'.");
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
case ',':
|
||||
x.back();
|
||||
return "";
|
||||
default:
|
||||
x.back();
|
||||
return x.nextTo(',');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of strings from a row of comma delimited values.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @return A JSONArray of strings.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
|
||||
JSONArray ja = new JSONArray();
|
||||
for (;;) {
|
||||
String value = getValue(x);
|
||||
char c = x.next();
|
||||
if (value == null ||
|
||||
(ja.length() == 0 && value.length() == 0 && c != ',')) {
|
||||
return null;
|
||||
}
|
||||
ja.put(value);
|
||||
for (;;) {
|
||||
if (c == ',') {
|
||||
break;
|
||||
}
|
||||
if (c != ' ') {
|
||||
if (c == '\n' || c == '\r' || c == 0) {
|
||||
return ja;
|
||||
}
|
||||
throw x.syntaxError("Bad character '" + c + "' (" +
|
||||
(int)c + ").");
|
||||
}
|
||||
c = x.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONObject from a row of comma delimited text, using a
|
||||
* parallel JSONArray of strings to provides the names of the elements.
|
||||
* @param names A JSONArray of names. This is commonly obtained from the
|
||||
* first row of a comma delimited text file using the rowToJSONArray
|
||||
* method.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @return A JSONObject combining the names and values.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
|
||||
throws JSONException {
|
||||
JSONArray ja = rowToJSONArray(x);
|
||||
return ja != null ? ja.toJSONObject(names) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text row from a JSONArray. Values containing
|
||||
* the comma character will be quoted. Troublesome characters may be
|
||||
* removed.
|
||||
* @param ja A JSONArray of strings.
|
||||
* @return A string ending in NEWLINE.
|
||||
*/
|
||||
public static String rowToString(JSONArray ja) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < ja.length(); i += 1) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
Object object = ja.opt(i);
|
||||
if (object != null) {
|
||||
String string = object.toString();
|
||||
if (string.length() > 0 && (string.indexOf(',') >= 0 ||
|
||||
string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 ||
|
||||
string.indexOf(0) >= 0 || string.charAt(0) == '"')) {
|
||||
sb.append('"');
|
||||
int length = string.length();
|
||||
for (int j = 0; j < length; j += 1) {
|
||||
char c = string.charAt(j);
|
||||
if (c >= ' ' && c != '"') {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
} else {
|
||||
sb.append(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('\n');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string,
|
||||
* using the first row as a source of names.
|
||||
* @param string The comma delimited text.
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string) throws JSONException {
|
||||
return toJSONArray(new JSONTokener(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string,
|
||||
* using the first row as a source of names.
|
||||
* @param x The JSONTokener containing the comma delimited text.
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
|
||||
return toJSONArray(rowToJSONArray(x), x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string
|
||||
* using a supplied JSONArray as the source of element names.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param string The comma delimited text.
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, String string)
|
||||
throws JSONException {
|
||||
return toJSONArray(names, new JSONTokener(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string
|
||||
* using a supplied JSONArray as the source of element names.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
|
||||
throws JSONException {
|
||||
if (names == null || names.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
JSONArray ja = new JSONArray();
|
||||
for (;;) {
|
||||
JSONObject jo = rowToJSONObject(names, x);
|
||||
if (jo == null) {
|
||||
break;
|
||||
}
|
||||
ja.put(jo);
|
||||
}
|
||||
if (ja.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
return ja;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text from a JSONArray of JSONObjects. The
|
||||
* first row will be a list of names obtained by inspecting the first
|
||||
* JSONObject.
|
||||
* @param ja A JSONArray of JSONObjects.
|
||||
* @return A comma delimited text.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONArray ja) throws JSONException {
|
||||
JSONObject jo = ja.optJSONObject(0);
|
||||
if (jo != null) {
|
||||
JSONArray names = jo.names();
|
||||
if (names != null) {
|
||||
return rowToString(names) + toString(names, ja);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text from a JSONArray of JSONObjects using
|
||||
* a provided list of names. The list of names is not included in the
|
||||
* output.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param ja A JSONArray of JSONObjects.
|
||||
* @return A comma delimited text.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONArray names, JSONArray ja)
|
||||
throws JSONException {
|
||||
if (names == null || names.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < ja.length(); i += 1) {
|
||||
JSONObject jo = ja.optJSONObject(i);
|
||||
if (jo != null) {
|
||||
sb.append(rowToString(jo.toJSONArray(names)));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
169
src/org/json/Cookie.java
Normal file
169
src/org/json/Cookie.java
Normal file
@ -0,0 +1,169 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert a web browser cookie specification to a JSONObject and back.
|
||||
* JSON and Cookies are both notations for name/value pairs.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class Cookie {
|
||||
|
||||
/**
|
||||
* Produce a copy of a string in which the characters '+', '%', '=', ';'
|
||||
* and control characters are replaced with "%hh". This is a gentle form
|
||||
* of URL encoding, attempting to cause as little distortion to the
|
||||
* string as possible. The characters '=' and ';' are meta characters in
|
||||
* cookies. By convention, they are escaped using the URL-encoding. This is
|
||||
* only a convention, not a standard. Often, cookies are expected to have
|
||||
* encoded values. We encode '=' and ';' because we must. We encode '%' and
|
||||
* '+' because they are meta characters in URL encoding.
|
||||
* @param string The source string.
|
||||
* @return The escaped result.
|
||||
*/
|
||||
public static String escape(String string) {
|
||||
char c;
|
||||
String s = string.trim();
|
||||
int length = s.length();
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
c = s.charAt(i);
|
||||
if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') {
|
||||
sb.append('%');
|
||||
sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16));
|
||||
sb.append(Character.forDigit((char)(c & 0x0f), 16));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a cookie specification string into a JSONObject. The string
|
||||
* will contain a name value pair separated by '='. The name and the value
|
||||
* will be unescaped, possibly converting '+' and '%' sequences. The
|
||||
* cookie properties may follow, separated by ';', also represented as
|
||||
* name=value (except the secure property, which does not have a value).
|
||||
* The name will be stored under the key "name", and the value will be
|
||||
* stored under the key "value". This method does not do checking or
|
||||
* validation of the parameters. It only converts the cookie string into
|
||||
* a JSONObject.
|
||||
* @param string The cookie specification string.
|
||||
* @return A JSONObject containing "name", "value", and possibly other
|
||||
* members.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
String name;
|
||||
JSONObject jo = new JSONObject();
|
||||
Object value;
|
||||
JSONTokener x = new JSONTokener(string);
|
||||
jo.put("name", x.nextTo('='));
|
||||
x.next('=');
|
||||
jo.put("value", x.nextTo(';'));
|
||||
x.next();
|
||||
while (x.more()) {
|
||||
name = unescape(x.nextTo("=;"));
|
||||
if (x.next() != '=') {
|
||||
if (name.equals("secure")) {
|
||||
value = Boolean.TRUE;
|
||||
} else {
|
||||
throw x.syntaxError("Missing '=' in cookie parameter.");
|
||||
}
|
||||
} else {
|
||||
value = unescape(x.nextTo(';'));
|
||||
x.next();
|
||||
}
|
||||
jo.put(name, value);
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into a cookie specification string. The JSONObject
|
||||
* must contain "name" and "value" members.
|
||||
* If the JSONObject contains "expires", "domain", "path", or "secure"
|
||||
* members, they will be appended to the cookie specification string.
|
||||
* All other members are ignored.
|
||||
* @param jo A JSONObject
|
||||
* @return A cookie specification string
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(escape(jo.getString("name")));
|
||||
sb.append("=");
|
||||
sb.append(escape(jo.getString("value")));
|
||||
if (jo.has("expires")) {
|
||||
sb.append(";expires=");
|
||||
sb.append(jo.getString("expires"));
|
||||
}
|
||||
if (jo.has("domain")) {
|
||||
sb.append(";domain=");
|
||||
sb.append(escape(jo.getString("domain")));
|
||||
}
|
||||
if (jo.has("path")) {
|
||||
sb.append(";path=");
|
||||
sb.append(escape(jo.getString("path")));
|
||||
}
|
||||
if (jo.optBoolean("secure")) {
|
||||
sb.append(";secure");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert <code>%</code><i>hh</i> sequences to single characters, and
|
||||
* convert plus to space.
|
||||
* @param string A string that may contain
|
||||
* <code>+</code> <small>(plus)</small> and
|
||||
* <code>%</code><i>hh</i> sequences.
|
||||
* @return The unescaped string.
|
||||
*/
|
||||
public static String unescape(String string) {
|
||||
int length = string.length();
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
char c = string.charAt(i);
|
||||
if (c == '+') {
|
||||
c = ' ';
|
||||
} else if (c == '%' && i + 2 < length) {
|
||||
int d = JSONTokener.dehexchar(string.charAt(i + 1));
|
||||
int e = JSONTokener.dehexchar(string.charAt(i + 2));
|
||||
if (d >= 0 && e >= 0) {
|
||||
c = (char)(d * 16 + e);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
89
src/org/json/CookieList.java
Normal file
89
src/org/json/CookieList.java
Normal file
@ -0,0 +1,89 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Convert a web browser cookie list string to a JSONObject and back.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class CookieList {
|
||||
|
||||
/**
|
||||
* Convert a cookie list into a JSONObject. A cookie list is a sequence
|
||||
* of name/value pairs. The names are separated from the values by '='.
|
||||
* The pairs are separated by ';'. The names and the values
|
||||
* will be unescaped, possibly converting '+' and '%' sequences.
|
||||
*
|
||||
* To add a cookie to a cooklist,
|
||||
* cookielistJSONObject.put(cookieJSONObject.getString("name"),
|
||||
* cookieJSONObject.getString("value"));
|
||||
* @param string A cookie list string
|
||||
* @return A JSONObject
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
JSONTokener x = new JSONTokener(string);
|
||||
while (x.more()) {
|
||||
String name = Cookie.unescape(x.nextTo('='));
|
||||
x.next('=');
|
||||
jo.put(name, Cookie.unescape(x.nextTo(';')));
|
||||
x.next();
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into a cookie list. A cookie list is a sequence
|
||||
* of name/value pairs. The names are separated from the values by '='.
|
||||
* The pairs are separated by ';'. The characters '%', '+', '=', and ';'
|
||||
* in the names and values are replaced by "%hh".
|
||||
* @param jo A JSONObject
|
||||
* @return A cookie list string
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
boolean b = false;
|
||||
Iterator<String> keys = jo.keys();
|
||||
String string;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (keys.hasNext()) {
|
||||
string = keys.next();
|
||||
if (!jo.isNull(string)) {
|
||||
if (b) {
|
||||
sb.append(';');
|
||||
}
|
||||
sb.append(Cookie.escape(string));
|
||||
sb.append("=");
|
||||
sb.append(Cookie.escape(jo.getString(string)));
|
||||
b = true;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
164
src/org/json/HTTP.java
Normal file
164
src/org/json/HTTP.java
Normal file
@ -0,0 +1,164 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Convert an HTTP header to a JSONObject and back.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class HTTP {
|
||||
|
||||
/** Carriage return/line feed. */
|
||||
public static final String CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* Convert an HTTP header string into a JSONObject. It can be a request
|
||||
* header or a response header. A request header will contain
|
||||
* <pre>{
|
||||
* Method: "POST" (for example),
|
||||
* "Request-URI": "/" (for example),
|
||||
* "HTTP-Version": "HTTP/1.1" (for example)
|
||||
* }</pre>
|
||||
* A response header will contain
|
||||
* <pre>{
|
||||
* "HTTP-Version": "HTTP/1.1" (for example),
|
||||
* "Status-Code": "200" (for example),
|
||||
* "Reason-Phrase": "OK" (for example)
|
||||
* }</pre>
|
||||
* In addition, the other parameters in the header will be captured, using
|
||||
* the HTTP field names as JSON names, so that <pre>
|
||||
* Date: Sun, 26 May 2002 18:06:04 GMT
|
||||
* Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
|
||||
* Cache-Control: no-cache</pre>
|
||||
* become
|
||||
* <pre>{...
|
||||
* Date: "Sun, 26 May 2002 18:06:04 GMT",
|
||||
* Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
|
||||
* "Cache-Control": "no-cache",
|
||||
* ...}</pre>
|
||||
* It does no further checking or conversion. It does not parse dates.
|
||||
* It does not do '%' transforms on URLs.
|
||||
* @param string An HTTP header string.
|
||||
* @return A JSONObject containing the elements and attributes
|
||||
* of the XML string.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
HTTPTokener x = new HTTPTokener(string);
|
||||
String token;
|
||||
|
||||
token = x.nextToken();
|
||||
if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) {
|
||||
|
||||
// Response
|
||||
|
||||
jo.put("HTTP-Version", token);
|
||||
jo.put("Status-Code", x.nextToken());
|
||||
jo.put("Reason-Phrase", x.nextTo('\0'));
|
||||
x.next();
|
||||
|
||||
} else {
|
||||
|
||||
// Request
|
||||
|
||||
jo.put("Method", token);
|
||||
jo.put("Request-URI", x.nextToken());
|
||||
jo.put("HTTP-Version", x.nextToken());
|
||||
}
|
||||
|
||||
// Fields
|
||||
|
||||
while (x.more()) {
|
||||
String name = x.nextTo(':');
|
||||
x.next(':');
|
||||
jo.put(name, x.nextTo('\0'));
|
||||
x.next();
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into an HTTP header. A request header must contain
|
||||
* <pre>{
|
||||
* Method: "POST" (for example),
|
||||
* "Request-URI": "/" (for example),
|
||||
* "HTTP-Version": "HTTP/1.1" (for example)
|
||||
* }</pre>
|
||||
* A response header must contain
|
||||
* <pre>{
|
||||
* "HTTP-Version": "HTTP/1.1" (for example),
|
||||
* "Status-Code": "200" (for example),
|
||||
* "Reason-Phrase": "OK" (for example)
|
||||
* }</pre>
|
||||
* Any other members of the JSONObject will be output as HTTP fields.
|
||||
* The result will end with two CRLF pairs.
|
||||
* @param jo A JSONObject
|
||||
* @return An HTTP header string.
|
||||
* @throws JSONException if the object does not contain enough
|
||||
* information.
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
Iterator<String> keys = jo.keys();
|
||||
String string;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (jo.has("Status-Code") && jo.has("Reason-Phrase")) {
|
||||
sb.append(jo.getString("HTTP-Version"));
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("Status-Code"));
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("Reason-Phrase"));
|
||||
} else if (jo.has("Method") && jo.has("Request-URI")) {
|
||||
sb.append(jo.getString("Method"));
|
||||
sb.append(' ');
|
||||
sb.append('"');
|
||||
sb.append(jo.getString("Request-URI"));
|
||||
sb.append('"');
|
||||
sb.append(' ');
|
||||
sb.append(jo.getString("HTTP-Version"));
|
||||
} else {
|
||||
throw new JSONException("Not enough material for an HTTP header.");
|
||||
}
|
||||
sb.append(CRLF);
|
||||
while (keys.hasNext()) {
|
||||
string = keys.next();
|
||||
if (!"HTTP-Version".equals(string) && !"Status-Code".equals(string) &&
|
||||
!"Reason-Phrase".equals(string) && !"Method".equals(string) &&
|
||||
!"Request-URI".equals(string) && !jo.isNull(string)) {
|
||||
sb.append(string);
|
||||
sb.append(": ");
|
||||
sb.append(jo.getString(string));
|
||||
sb.append(CRLF);
|
||||
}
|
||||
}
|
||||
sb.append(CRLF);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
77
src/org/json/HTTPTokener.java
Normal file
77
src/org/json/HTTPTokener.java
Normal file
@ -0,0 +1,77 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The HTTPTokener extends the JSONTokener to provide additional methods
|
||||
* for the parsing of HTTP headers.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class HTTPTokener extends JSONTokener {
|
||||
|
||||
/**
|
||||
* Construct an HTTPTokener from a string.
|
||||
* @param string A source string.
|
||||
*/
|
||||
public HTTPTokener(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next token or string. This is used in parsing HTTP headers.
|
||||
* @throws JSONException
|
||||
* @return A String.
|
||||
*/
|
||||
public String nextToken() throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
if (c == '"' || c == '\'') {
|
||||
q = c;
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (c < ' ') {
|
||||
throw syntaxError("Unterminated string.");
|
||||
}
|
||||
if (c == q) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (c == 0 || Character.isWhitespace(c)) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
c = next();
|
||||
}
|
||||
}
|
||||
}
|
1200
src/org/json/JSONArray.java
Normal file
1200
src/org/json/JSONArray.java
Normal file
File diff suppressed because it is too large
Load Diff
45
src/org/json/JSONException.java
Normal file
45
src/org/json/JSONException.java
Normal file
@ -0,0 +1,45 @@
|
||||
package org.json;
|
||||
|
||||
/**
|
||||
* The JSONException is thrown by the JSON.org classes when things are amiss.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class JSONException extends RuntimeException {
|
||||
/** Serialization ID */
|
||||
private static final long serialVersionUID = 0;
|
||||
|
||||
/**
|
||||
* Constructs a JSONException with an explanatory message.
|
||||
*
|
||||
* @param message
|
||||
* Detail about the reason for the exception.
|
||||
*/
|
||||
public JSONException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a JSONException with an explanatory message and cause.
|
||||
*
|
||||
* @param message
|
||||
* Detail about the reason for the exception.
|
||||
* @param cause
|
||||
* The cause.
|
||||
*/
|
||||
public JSONException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new JSONException with the specified cause.
|
||||
*
|
||||
* @param cause
|
||||
* The cause.
|
||||
*/
|
||||
public JSONException(final Throwable cause) {
|
||||
super(cause.getMessage(), cause);
|
||||
}
|
||||
|
||||
}
|
552
src/org/json/JSONML.java
Normal file
552
src/org/json/JSONML.java
Normal file
@ -0,0 +1,552 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2008 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* This provides static methods to convert an XML text into a JSONArray or
|
||||
* JSONObject, and to covert a JSONArray or JSONObject into an XML text using
|
||||
* the JsonML transform.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2016-01-30
|
||||
*/
|
||||
public class JSONML {
|
||||
/**
|
||||
* Parse XML values and store them in a JSONArray.
|
||||
* @param x The XMLTokener containing the source string.
|
||||
* @param arrayForm true if array form, false if object form.
|
||||
* @param ja The JSONArray that is containing the current tag or null
|
||||
* if we are at the outermost level.
|
||||
* @param keepStrings Don't type-convert text nodes and attibute values
|
||||
* @return A JSONArray if the value is the outermost tag, otherwise null.
|
||||
* @throws JSONException
|
||||
*/
|
||||
private static Object parse(
|
||||
XMLTokener x,
|
||||
boolean arrayForm,
|
||||
JSONArray ja,
|
||||
boolean keepStrings
|
||||
) throws JSONException {
|
||||
String attribute;
|
||||
char c;
|
||||
String closeTag = null;
|
||||
int i;
|
||||
JSONArray newja = null;
|
||||
JSONObject newjo = null;
|
||||
Object token;
|
||||
String tagName = null;
|
||||
|
||||
// Test for and skip past these forms:
|
||||
// <!-- ... -->
|
||||
// <![ ... ]]>
|
||||
// <! ... >
|
||||
// <? ... ?>
|
||||
|
||||
while (true) {
|
||||
if (!x.more()) {
|
||||
throw x.syntaxError("Bad XML");
|
||||
}
|
||||
token = x.nextContent();
|
||||
if (token == XML.LT) {
|
||||
token = x.nextToken();
|
||||
if (token instanceof Character) {
|
||||
if (token == XML.SLASH) {
|
||||
|
||||
// Close tag </
|
||||
|
||||
token = x.nextToken();
|
||||
if (!(token instanceof String)) {
|
||||
throw new JSONException(
|
||||
"Expected a closing name instead of '" +
|
||||
token + "'.");
|
||||
}
|
||||
if (x.nextToken() != XML.GT) {
|
||||
throw x.syntaxError("Misshaped close tag");
|
||||
}
|
||||
return token;
|
||||
} else if (token == XML.BANG) {
|
||||
|
||||
// <!
|
||||
|
||||
c = x.next();
|
||||
if (c == '-') {
|
||||
if (x.next() == '-') {
|
||||
x.skipPast("-->");
|
||||
} else {
|
||||
x.back();
|
||||
}
|
||||
} else if (c == '[') {
|
||||
token = x.nextToken();
|
||||
if (token.equals("CDATA") && x.next() == '[') {
|
||||
if (ja != null) {
|
||||
ja.put(x.nextCDATA());
|
||||
}
|
||||
} else {
|
||||
throw x.syntaxError("Expected 'CDATA['");
|
||||
}
|
||||
} else {
|
||||
i = 1;
|
||||
do {
|
||||
token = x.nextMeta();
|
||||
if (token == null) {
|
||||
throw x.syntaxError("Missing '>' after '<!'.");
|
||||
} else if (token == XML.LT) {
|
||||
i += 1;
|
||||
} else if (token == XML.GT) {
|
||||
i -= 1;
|
||||
}
|
||||
} while (i > 0);
|
||||
}
|
||||
} else if (token == XML.QUEST) {
|
||||
|
||||
// <?
|
||||
|
||||
x.skipPast("?>");
|
||||
} else {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
|
||||
// Open tag <
|
||||
|
||||
} else {
|
||||
if (!(token instanceof String)) {
|
||||
throw x.syntaxError("Bad tagName '" + token + "'.");
|
||||
}
|
||||
tagName = (String)token;
|
||||
newja = new JSONArray();
|
||||
newjo = new JSONObject();
|
||||
if (arrayForm) {
|
||||
newja.put(tagName);
|
||||
if (ja != null) {
|
||||
ja.put(newja);
|
||||
}
|
||||
} else {
|
||||
newjo.put("tagName", tagName);
|
||||
if (ja != null) {
|
||||
ja.put(newjo);
|
||||
}
|
||||
}
|
||||
token = null;
|
||||
for (;;) {
|
||||
if (token == null) {
|
||||
token = x.nextToken();
|
||||
}
|
||||
if (token == null) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if (!(token instanceof String)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// attribute = value
|
||||
|
||||
attribute = (String)token;
|
||||
if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {
|
||||
throw x.syntaxError("Reserved attribute.");
|
||||
}
|
||||
token = x.nextToken();
|
||||
if (token == XML.EQ) {
|
||||
token = x.nextToken();
|
||||
if (!(token instanceof String)) {
|
||||
throw x.syntaxError("Missing value");
|
||||
}
|
||||
newjo.accumulate(attribute, keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token));
|
||||
token = null;
|
||||
} else {
|
||||
newjo.accumulate(attribute, "");
|
||||
}
|
||||
}
|
||||
if (arrayForm && newjo.length() > 0) {
|
||||
newja.put(newjo);
|
||||
}
|
||||
|
||||
// Empty tag <.../>
|
||||
|
||||
if (token == XML.SLASH) {
|
||||
if (x.nextToken() != XML.GT) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if (ja == null) {
|
||||
if (arrayForm) {
|
||||
return newja;
|
||||
}
|
||||
return newjo;
|
||||
}
|
||||
|
||||
// Content, between <...> and </...>
|
||||
|
||||
} else {
|
||||
if (token != XML.GT) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
closeTag = (String)parse(x, arrayForm, newja, keepStrings);
|
||||
if (closeTag != null) {
|
||||
if (!closeTag.equals(tagName)) {
|
||||
throw x.syntaxError("Mismatched '" + tagName +
|
||||
"' and '" + closeTag + "'");
|
||||
}
|
||||
tagName = null;
|
||||
if (!arrayForm && newja.length() > 0) {
|
||||
newjo.put("childNodes", newja);
|
||||
}
|
||||
if (ja == null) {
|
||||
if (arrayForm) {
|
||||
return newja;
|
||||
}
|
||||
return newjo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ja != null) {
|
||||
ja.put(token instanceof String
|
||||
? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token)
|
||||
: token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child tags.
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param string The source string.
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONArray
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string) throws JSONException {
|
||||
return (JSONArray)parse(new XMLTokener(string), true, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child tags.
|
||||
* As opposed to toJSONArray this method does not attempt to convert
|
||||
* any text node or attribute value to any type
|
||||
* but just leaves it as a string.
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param string The source string.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONArray
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException {
|
||||
return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child content and tags.
|
||||
* As opposed to toJSONArray this method does not attempt to convert
|
||||
* any text node or attribute value to any type
|
||||
* but just leaves it as a string.
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param x An XMLTokener.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONArray
|
||||
*/
|
||||
public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException {
|
||||
return (JSONArray)parse(x, true, null, keepStrings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONArray using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONArray in which the first element is the tag name. If the tag has
|
||||
* attributes, then the second element will be JSONObject containing the
|
||||
* name/value pairs. If the tag contains children, then strings and
|
||||
* JSONArrays will represent the child content and tags.
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param x An XMLTokener.
|
||||
* @return A JSONArray containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONArray
|
||||
*/
|
||||
public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
|
||||
return (JSONArray)parse(x, true, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then
|
||||
* the attributes will be in the JSONObject as properties. If the tag
|
||||
* contains children, the object will have a "childNodes" property which
|
||||
* will be an array of strings and JsonML JSONObjects.
|
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param string The XML source text.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONObject
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
return (JSONObject)parse(new XMLTokener(string), false, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then
|
||||
* the attributes will be in the JSONObject as properties. If the tag
|
||||
* contains children, the object will have a "childNodes" property which
|
||||
* will be an array of strings and JsonML JSONObjects.
|
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param string The XML source text.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONObject
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
|
||||
return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then
|
||||
* the attributes will be in the JSONObject as properties. If the tag
|
||||
* contains children, the object will have a "childNodes" property which
|
||||
* will be an array of strings and JsonML JSONObjects.
|
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param x An XMLTokener of the XML source text.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONObject
|
||||
*/
|
||||
public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
|
||||
return (JSONObject)parse(x, false, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject using the JsonML transform. Each XML tag is represented as
|
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then
|
||||
* the attributes will be in the JSONObject as properties. If the tag
|
||||
* contains children, the object will have a "childNodes" property which
|
||||
* will be an array of strings and JsonML JSONObjects.
|
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
|
||||
* @param x An XMLTokener of the XML source text.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown on error converting to a JSONObject
|
||||
*/
|
||||
public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException {
|
||||
return (JSONObject)parse(x, false, null, keepStrings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the JSONML transformation, making an XML text from a JSONArray.
|
||||
* @param ja A JSONArray.
|
||||
* @return An XML string.
|
||||
* @throws JSONException Thrown on error converting to a string
|
||||
*/
|
||||
public static String toString(JSONArray ja) throws JSONException {
|
||||
int i;
|
||||
JSONObject jo;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
int length;
|
||||
Object object;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String tagName;
|
||||
String value;
|
||||
|
||||
// Emit <tagName
|
||||
|
||||
tagName = ja.getString(0);
|
||||
XML.noSpace(tagName);
|
||||
tagName = XML.escape(tagName);
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
|
||||
object = ja.opt(1);
|
||||
if (object instanceof JSONObject) {
|
||||
i = 2;
|
||||
jo = (JSONObject)object;
|
||||
|
||||
// Emit the attributes
|
||||
|
||||
keys = jo.keys();
|
||||
while (keys.hasNext()) {
|
||||
key = keys.next();
|
||||
XML.noSpace(key);
|
||||
value = jo.optString(key);
|
||||
if (value != null) {
|
||||
sb.append(' ');
|
||||
sb.append(XML.escape(key));
|
||||
sb.append('=');
|
||||
sb.append('"');
|
||||
sb.append(XML.escape(value));
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i = 1;
|
||||
}
|
||||
|
||||
// Emit content in body
|
||||
|
||||
length = ja.length();
|
||||
if (i >= length) {
|
||||
sb.append('/');
|
||||
sb.append('>');
|
||||
} else {
|
||||
sb.append('>');
|
||||
do {
|
||||
object = ja.get(i);
|
||||
i += 1;
|
||||
if (object != null) {
|
||||
if (object instanceof String) {
|
||||
sb.append(XML.escape(object.toString()));
|
||||
} else if (object instanceof JSONObject) {
|
||||
sb.append(toString((JSONObject)object));
|
||||
} else if (object instanceof JSONArray) {
|
||||
sb.append(toString((JSONArray)object));
|
||||
} else {
|
||||
sb.append(object.toString());
|
||||
}
|
||||
}
|
||||
} while (i < length);
|
||||
sb.append('<');
|
||||
sb.append('/');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the JSONML transformation, making an XML text from a JSONObject.
|
||||
* The JSONObject must contain a "tagName" property. If it has children,
|
||||
* then it must have a "childNodes" property containing an array of objects.
|
||||
* The other properties are attributes with string values.
|
||||
* @param jo A JSONObject.
|
||||
* @return An XML string.
|
||||
* @throws JSONException Thrown on error converting to a string
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i;
|
||||
JSONArray ja;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
int length;
|
||||
Object object;
|
||||
String tagName;
|
||||
String value;
|
||||
|
||||
//Emit <tagName
|
||||
|
||||
tagName = jo.optString("tagName");
|
||||
if (tagName == null) {
|
||||
return XML.escape(jo.toString());
|
||||
}
|
||||
XML.noSpace(tagName);
|
||||
tagName = XML.escape(tagName);
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
|
||||
//Emit the attributes
|
||||
|
||||
keys = jo.keys();
|
||||
while (keys.hasNext()) {
|
||||
key = keys.next();
|
||||
if (!"tagName".equals(key) && !"childNodes".equals(key)) {
|
||||
XML.noSpace(key);
|
||||
value = jo.optString(key);
|
||||
if (value != null) {
|
||||
sb.append(' ');
|
||||
sb.append(XML.escape(key));
|
||||
sb.append('=');
|
||||
sb.append('"');
|
||||
sb.append(XML.escape(value));
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Emit content in body
|
||||
|
||||
ja = jo.optJSONArray("childNodes");
|
||||
if (ja == null) {
|
||||
sb.append('/');
|
||||
sb.append('>');
|
||||
} else {
|
||||
sb.append('>');
|
||||
length = ja.length();
|
||||
for (i = 0; i < length; i += 1) {
|
||||
object = ja.get(i);
|
||||
if (object != null) {
|
||||
if (object instanceof String) {
|
||||
sb.append(XML.escape(object.toString()));
|
||||
} else if (object instanceof JSONObject) {
|
||||
sb.append(toString((JSONObject)object));
|
||||
} else if (object instanceof JSONArray) {
|
||||
sb.append(toString((JSONArray)object));
|
||||
} else {
|
||||
sb.append(object.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('<');
|
||||
sb.append('/');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
1938
src/org/json/JSONObject.java
Normal file
1938
src/org/json/JSONObject.java
Normal file
File diff suppressed because it is too large
Load Diff
267
src/org/json/JSONPointer.java
Normal file
267
src/org/json/JSONPointer.java
Normal file
@ -0,0 +1,267 @@
|
||||
package org.json;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A JSON Pointer is a simple query language defined for JSON documents by
|
||||
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
|
||||
*
|
||||
* In a nutshell, JSONPointer allows the user to navigate into a JSON document
|
||||
* using strings, and retrieve targeted objects, like a simple form of XPATH.
|
||||
* Path segments are separated by the '/' char, which signifies the root of
|
||||
* the document when it appears as the first char of the string. Array
|
||||
* elements are navigated using ordinals, counting from 0. JSONPointer strings
|
||||
* may be extended to any arbitrary number of segments. If the navigation
|
||||
* is successful, the matched item is returned. A matched item may be a
|
||||
* JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building
|
||||
* fails, an appropriate exception is thrown. If the navigation fails to find
|
||||
* a match, a JSONPointerException is thrown.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2016-05-14
|
||||
*/
|
||||
public class JSONPointer {
|
||||
|
||||
// used for URL encoding and decoding
|
||||
private static final String ENCODING = "utf-8";
|
||||
|
||||
/**
|
||||
* This class allows the user to build a JSONPointer in steps, using
|
||||
* exactly one segment in each step.
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
// Segments for the eventual JSONPointer string
|
||||
private final List<String> refTokens = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Creates a {@code JSONPointer} instance using the tokens previously set using the
|
||||
* {@link #append(String)} method calls.
|
||||
*/
|
||||
public JSONPointer build() {
|
||||
return new JSONPointer(refTokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an arbitary token to the list of reference tokens. It can be any non-null value.
|
||||
*
|
||||
* Unlike in the case of JSON string or URI fragment representation of JSON pointers, the
|
||||
* argument of this method MUST NOT be escaped. If you want to query the property called
|
||||
* {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no
|
||||
* need to escape it as {@code "a~0b"}.
|
||||
*
|
||||
* @param token the new token to be appended to the list
|
||||
* @return {@code this}
|
||||
* @throws NullPointerException if {@code token} is null
|
||||
*/
|
||||
public Builder append(String token) {
|
||||
if (token == null) {
|
||||
throw new NullPointerException("token cannot be null");
|
||||
}
|
||||
refTokens.add(token);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an integer to the reference token list. Although not necessarily, mostly this token will
|
||||
* denote an array index.
|
||||
*
|
||||
* @param arrayIndex the array index to be added to the token list
|
||||
* @return {@code this}
|
||||
*/
|
||||
public Builder append(int arrayIndex) {
|
||||
refTokens.add(String.valueOf(arrayIndex));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method for {@link Builder}. Example usage:
|
||||
*
|
||||
* <pre><code>
|
||||
* JSONPointer pointer = JSONPointer.builder()
|
||||
* .append("obj")
|
||||
* .append("other~key").append("another/key")
|
||||
* .append("\"")
|
||||
* .append(0)
|
||||
* .build();
|
||||
* </code></pre>
|
||||
*
|
||||
* @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained
|
||||
* {@link Builder#append(String)} calls.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
// Segments for the JSONPointer string
|
||||
private final List<String> refTokens;
|
||||
|
||||
/**
|
||||
* Pre-parses and initializes a new {@code JSONPointer} instance. If you want to
|
||||
* evaluate the same JSON Pointer on different JSON documents then it is recommended
|
||||
* to keep the {@code JSONPointer} instances due to performance considerations.
|
||||
*
|
||||
* @param pointer the JSON String or URI Fragment representation of the JSON pointer.
|
||||
* @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer
|
||||
*/
|
||||
public JSONPointer(String pointer) {
|
||||
if (pointer == null) {
|
||||
throw new NullPointerException("pointer cannot be null");
|
||||
}
|
||||
if (pointer.isEmpty() || pointer.equals("#")) {
|
||||
refTokens = Collections.emptyList();
|
||||
return;
|
||||
}
|
||||
if (pointer.startsWith("#/")) {
|
||||
pointer = pointer.substring(2);
|
||||
try {
|
||||
pointer = URLDecoder.decode(pointer, ENCODING);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else if (pointer.startsWith("/")) {
|
||||
pointer = pointer.substring(1);
|
||||
} else {
|
||||
throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'");
|
||||
}
|
||||
refTokens = new ArrayList<String>();
|
||||
for (String token : pointer.split("/")) {
|
||||
refTokens.add(unescape(token));
|
||||
}
|
||||
}
|
||||
|
||||
public JSONPointer(List<String> refTokens) {
|
||||
this.refTokens = new ArrayList<String>(refTokens);
|
||||
}
|
||||
|
||||
private String unescape(String token) {
|
||||
return token.replace("~1", "/").replace("~0", "~")
|
||||
.replace("\\\"", "\"")
|
||||
.replace("\\\\", "\\");
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates this JSON Pointer on the given {@code document}. The {@code document}
|
||||
* is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty
|
||||
* JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the
|
||||
* returned value will be {@code document} itself.
|
||||
*
|
||||
* @param document the JSON document which should be the subject of querying.
|
||||
* @return the result of the evaluation
|
||||
* @throws JSONPointerException if an error occurs during evaluation
|
||||
*/
|
||||
public Object queryFrom(Object document) {
|
||||
if (refTokens.isEmpty()) {
|
||||
return document;
|
||||
}
|
||||
Object current = document;
|
||||
for (String token : refTokens) {
|
||||
if (current instanceof JSONObject) {
|
||||
current = ((JSONObject) current).opt(unescape(token));
|
||||
} else if (current instanceof JSONArray) {
|
||||
current = readByIndexToken(current, token);
|
||||
} else {
|
||||
throw new JSONPointerException(format(
|
||||
"value [%s] is not an array or object therefore its key %s cannot be resolved", current,
|
||||
token));
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a JSONArray element by ordinal position
|
||||
* @param current the JSONArray to be evaluated
|
||||
* @param indexToken the array index in string form
|
||||
* @return the matched object. If no matching item is found a
|
||||
* JSONPointerException is thrown
|
||||
*/
|
||||
private Object readByIndexToken(Object current, String indexToken) {
|
||||
try {
|
||||
int index = Integer.parseInt(indexToken);
|
||||
JSONArray currentArr = (JSONArray) current;
|
||||
if (index >= currentArr.length()) {
|
||||
throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index,
|
||||
currentArr.length()));
|
||||
}
|
||||
return currentArr.get(index);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JSONPointerException(format("%s is not an array index", indexToken), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the JSONPointer path value using string
|
||||
* representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder rval = new StringBuilder("");
|
||||
for (String token: refTokens) {
|
||||
rval.append('/').append(escape(token));
|
||||
}
|
||||
return rval.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes path segment values to an unambiguous form.
|
||||
* The escape char to be inserted is '~'. The chars to be escaped
|
||||
* are ~, which maps to ~0, and /, which maps to ~1. Backslashes
|
||||
* and double quote chars are also escaped.
|
||||
* @param token the JSONPointer segment value to be escaped
|
||||
* @return the escaped value for the token
|
||||
*/
|
||||
private String escape(String token) {
|
||||
return token.replace("~", "~0")
|
||||
.replace("/", "~1")
|
||||
.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the JSONPointer path value using URI
|
||||
* fragment identifier representation
|
||||
*/
|
||||
public String toURIFragment() {
|
||||
try {
|
||||
StringBuilder rval = new StringBuilder("#");
|
||||
for (String token : refTokens) {
|
||||
rval.append('/').append(URLEncoder.encode(token, ENCODING));
|
||||
}
|
||||
return rval.toString();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
45
src/org/json/JSONPointerException.java
Normal file
45
src/org/json/JSONPointerException.java
Normal file
@ -0,0 +1,45 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The JSONPointerException is thrown by {@link JSONPointer} if an error occurs
|
||||
* during evaluating a pointer.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2016-05-13
|
||||
*/
|
||||
public class JSONPointerException extends JSONException {
|
||||
private static final long serialVersionUID = 8872944667561856751L;
|
||||
|
||||
public JSONPointerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JSONPointerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
18
src/org/json/JSONString.java
Normal file
18
src/org/json/JSONString.java
Normal file
@ -0,0 +1,18 @@
|
||||
package org.json;
|
||||
/**
|
||||
* The <code>JSONString</code> interface allows a <code>toJSONString()</code>
|
||||
* method so that a class can change the behavior of
|
||||
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
|
||||
* and <code>JSONWriter.value(</code>Object<code>)</code>. The
|
||||
* <code>toJSONString</code> method will be used instead of the default behavior
|
||||
* of using the Object's <code>toString()</code> method and quoting the result.
|
||||
*/
|
||||
public interface JSONString {
|
||||
/**
|
||||
* The <code>toJSONString</code> method allows a class to produce its own JSON
|
||||
* serialization.
|
||||
*
|
||||
* @return A strictly syntactically correct JSON text.
|
||||
*/
|
||||
public String toJSONString();
|
||||
}
|
78
src/org/json/JSONStringer.java
Normal file
78
src/org/json/JSONStringer.java
Normal file
@ -0,0 +1,78 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* JSONStringer provides a quick and convenient way of producing JSON text.
|
||||
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||
* added, so the results are ready for transmission or storage. Each instance of
|
||||
* JSONStringer can produce one JSON text.
|
||||
* <p>
|
||||
* A JSONStringer instance provides a <code>value</code> method for appending
|
||||
* values to the
|
||||
* text, and a <code>key</code>
|
||||
* method for adding keys before values in objects. There are <code>array</code>
|
||||
* and <code>endArray</code> methods that make and bound array values, and
|
||||
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||
* object values. All of these methods return the JSONWriter instance,
|
||||
* permitting cascade style. For example, <pre>
|
||||
* myString = new JSONStringer()
|
||||
* .object()
|
||||
* .key("JSON")
|
||||
* .value("Hello, World!")
|
||||
* .endObject()
|
||||
* .toString();</pre> which produces the string <pre>
|
||||
* {"JSON":"Hello, World!"}</pre>
|
||||
* <p>
|
||||
* The first method called must be <code>array</code> or <code>object</code>.
|
||||
* There are no methods for adding commas or colons. JSONStringer adds them for
|
||||
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||
* <p>
|
||||
* This can sometimes be easier than using a JSONObject to build a string.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class JSONStringer extends JSONWriter {
|
||||
/**
|
||||
* Make a fresh JSONStringer. It can be used to build one JSON text.
|
||||
*/
|
||||
public JSONStringer() {
|
||||
super(new StringWriter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON text. This method is used to obtain the product of the
|
||||
* JSONStringer instance. It will return <code>null</code> if there was a
|
||||
* problem in the construction of the JSON text (such as the calls to
|
||||
* <code>array</code> were not properly balanced with calls to
|
||||
* <code>endArray</code>).
|
||||
* @return The JSON text.
|
||||
*/
|
||||
public String toString() {
|
||||
return this.mode == 'd' ? this.writer.toString() : null;
|
||||
}
|
||||
}
|
475
src/org/json/JSONTokener.java
Normal file
475
src/org/json/JSONTokener.java
Normal file
@ -0,0 +1,475 @@
|
||||
package org.json;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A JSONTokener takes a source string and extracts characters and tokens from
|
||||
* it. It is used by the JSONObject and JSONArray constructors to parse
|
||||
* JSON source strings.
|
||||
* @author JSON.org
|
||||
* @version 2014-05-03
|
||||
*/
|
||||
public class JSONTokener {
|
||||
|
||||
private long character;
|
||||
private boolean eof;
|
||||
private long index;
|
||||
private long line;
|
||||
private char previous;
|
||||
private Reader reader;
|
||||
private boolean usePrevious;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a Reader.
|
||||
*
|
||||
* @param reader A reader.
|
||||
*/
|
||||
public JSONTokener(Reader reader) {
|
||||
this.reader = reader.markSupported()
|
||||
? reader
|
||||
: new BufferedReader(reader);
|
||||
this.eof = false;
|
||||
this.usePrevious = false;
|
||||
this.previous = 0;
|
||||
this.index = 0;
|
||||
this.character = 1;
|
||||
this.line = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from an InputStream.
|
||||
* @param inputStream The source.
|
||||
*/
|
||||
public JSONTokener(InputStream inputStream) {
|
||||
this(new InputStreamReader(inputStream));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a string.
|
||||
*
|
||||
* @param s A source string.
|
||||
*/
|
||||
public JSONTokener(String s) {
|
||||
this(new StringReader(s));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Back up one character. This provides a sort of lookahead capability,
|
||||
* so that you can test for a digit or letter before attempting to parse
|
||||
* the next number or identifier.
|
||||
* @throws JSONException Thrown if trying to step back more than 1 step
|
||||
* or if already at the start of the string
|
||||
*/
|
||||
public void back() throws JSONException {
|
||||
if (this.usePrevious || this.index <= 0) {
|
||||
throw new JSONException("Stepping back two steps is not supported");
|
||||
}
|
||||
this.index -= 1;
|
||||
this.character -= 1;
|
||||
this.usePrevious = true;
|
||||
this.eof = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the hex value of a character (base16).
|
||||
* @param c A character between '0' and '9' or between 'A' and 'F' or
|
||||
* between 'a' and 'f'.
|
||||
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
||||
*/
|
||||
public static int dehexchar(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - ('A' - 10);
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - ('a' - 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if at the end of the file and we didn't step back
|
||||
*/
|
||||
public boolean end() {
|
||||
return this.eof && !this.usePrevious;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the source string still contains characters that next()
|
||||
* can consume.
|
||||
* @return true if not yet at the end of the source.
|
||||
* @throws JSONException thrown if there is an error stepping forward
|
||||
* or backward while checking for more data.
|
||||
*/
|
||||
public boolean more() throws JSONException {
|
||||
this.next();
|
||||
if (this.end()) {
|
||||
return false;
|
||||
}
|
||||
this.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next character in the source string.
|
||||
*
|
||||
* @return The next character, or 0 if past the end of the source string.
|
||||
* @throws JSONException Thrown if there is an error reading the source string.
|
||||
*/
|
||||
public char next() throws JSONException {
|
||||
int c;
|
||||
if (this.usePrevious) {
|
||||
this.usePrevious = false;
|
||||
c = this.previous;
|
||||
} else {
|
||||
try {
|
||||
c = this.reader.read();
|
||||
} catch (IOException exception) {
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
|
||||
if (c <= 0) { // End of stream
|
||||
this.eof = true;
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
this.index += 1;
|
||||
if (this.previous == '\r') {
|
||||
this.line += 1;
|
||||
this.character = c == '\n' ? 0 : 1;
|
||||
} else if (c == '\n') {
|
||||
this.line += 1;
|
||||
this.character = 0;
|
||||
} else {
|
||||
this.character += 1;
|
||||
}
|
||||
this.previous = (char) c;
|
||||
return this.previous;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consume the next character, and check that it matches a specified
|
||||
* character.
|
||||
* @param c The character to match.
|
||||
* @return The character.
|
||||
* @throws JSONException if the character does not match.
|
||||
*/
|
||||
public char next(char c) throws JSONException {
|
||||
char n = this.next();
|
||||
if (n != c) {
|
||||
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
|
||||
n + "'");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next n characters.
|
||||
*
|
||||
* @param n The number of characters to take.
|
||||
* @return A string of n characters.
|
||||
* @throws JSONException
|
||||
* Substring bounds error if there are not
|
||||
* n characters remaining in the source string.
|
||||
*/
|
||||
public String next(int n) throws JSONException {
|
||||
if (n == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char[] chars = new char[n];
|
||||
int pos = 0;
|
||||
|
||||
while (pos < n) {
|
||||
chars[pos] = this.next();
|
||||
if (this.end()) {
|
||||
throw this.syntaxError("Substring bounds error");
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next char in the string, skipping whitespace.
|
||||
* @throws JSONException Thrown if there is an error reading the source string.
|
||||
* @return A character, or 0 if there are no more characters.
|
||||
*/
|
||||
public char nextClean() throws JSONException {
|
||||
for (;;) {
|
||||
char c = this.next();
|
||||
if (c == 0 || c > ' ') {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the characters up to the next close quote character.
|
||||
* Backslash processing is done. The formal JSON format does not
|
||||
* allow strings in single quotes, but an implementation is allowed to
|
||||
* accept them.
|
||||
* @param quote The quoting character, either
|
||||
* <code>"</code> <small>(double quote)</small> or
|
||||
* <code>'</code> <small>(single quote)</small>.
|
||||
* @return A String.
|
||||
* @throws JSONException Unterminated string.
|
||||
*/
|
||||
public String nextString(char quote) throws JSONException {
|
||||
char c;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
case 0:
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw this.syntaxError("Unterminated string");
|
||||
case '\\':
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
case 'b':
|
||||
sb.append('\b');
|
||||
break;
|
||||
case 't':
|
||||
sb.append('\t');
|
||||
break;
|
||||
case 'n':
|
||||
sb.append('\n');
|
||||
break;
|
||||
case 'f':
|
||||
sb.append('\f');
|
||||
break;
|
||||
case 'r':
|
||||
sb.append('\r');
|
||||
break;
|
||||
case 'u':
|
||||
try {
|
||||
sb.append((char)Integer.parseInt(this.next(4), 16));
|
||||
} catch (NumberFormatException e) {
|
||||
throw this.syntaxError("Illegal escape.", e);
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '/':
|
||||
sb.append(c);
|
||||
break;
|
||||
default:
|
||||
throw this.syntaxError("Illegal escape.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (c == quote) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the text up but not including the specified character or the
|
||||
* end of line, whichever comes first.
|
||||
* @param delimiter A delimiter character.
|
||||
* @return A string.
|
||||
* @throws JSONException Thrown if there is an error while searching
|
||||
* for the delimiter
|
||||
*/
|
||||
public String nextTo(char delimiter) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
char c = this.next();
|
||||
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the text up but not including one of the specified delimiter
|
||||
* characters or the end of line, whichever comes first.
|
||||
* @param delimiters A set of delimiter characters.
|
||||
* @return A string, trimmed.
|
||||
* @throws JSONException Thrown if there is an error while searching
|
||||
* for the delimiter
|
||||
*/
|
||||
public String nextTo(String delimiters) throws JSONException {
|
||||
char c;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = this.next();
|
||||
if (delimiters.indexOf(c) >= 0 || c == 0 ||
|
||||
c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be a Boolean, Double, Integer,
|
||||
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||
* @throws JSONException If syntax error.
|
||||
*
|
||||
* @return An object.
|
||||
*/
|
||||
public Object nextValue() throws JSONException {
|
||||
char c = this.nextClean();
|
||||
String string;
|
||||
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\'':
|
||||
return this.nextString(c);
|
||||
case '{':
|
||||
this.back();
|
||||
return new JSONObject(this);
|
||||
case '[':
|
||||
this.back();
|
||||
return new JSONArray(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle unquoted text. This could be the values true, false, or
|
||||
* null, or it can be a number. An implementation (such as this one)
|
||||
* is allowed to also accept non-standard forms.
|
||||
*
|
||||
* Accumulate characters until we reach the end of the text or a
|
||||
* formatting character.
|
||||
*/
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
|
||||
sb.append(c);
|
||||
c = this.next();
|
||||
}
|
||||
this.back();
|
||||
|
||||
string = sb.toString().trim();
|
||||
if ("".equals(string)) {
|
||||
throw this.syntaxError("Missing value");
|
||||
}
|
||||
return JSONObject.stringToValue(string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skip characters until the next character is the requested character.
|
||||
* If the requested character is not found, no characters are skipped.
|
||||
* @param to A character to skip to.
|
||||
* @return The requested character, or zero if the requested character
|
||||
* is not found.
|
||||
* @throws JSONException Thrown if there is an error while searching
|
||||
* for the to character
|
||||
*/
|
||||
public char skipTo(char to) throws JSONException {
|
||||
char c;
|
||||
try {
|
||||
long startIndex = this.index;
|
||||
long startCharacter = this.character;
|
||||
long startLine = this.line;
|
||||
this.reader.mark(1000000);
|
||||
do {
|
||||
c = this.next();
|
||||
if (c == 0) {
|
||||
this.reader.reset();
|
||||
this.index = startIndex;
|
||||
this.character = startCharacter;
|
||||
this.line = startLine;
|
||||
return c;
|
||||
}
|
||||
} while (c != to);
|
||||
} catch (IOException exception) {
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
this.back();
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a JSONException to signal a syntax error.
|
||||
*
|
||||
* @param message The error message.
|
||||
* @return A JSONException object, suitable for throwing
|
||||
*/
|
||||
public JSONException syntaxError(String message) {
|
||||
return new JSONException(message + this.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a JSONException to signal a syntax error.
|
||||
*
|
||||
* @param message The error message.
|
||||
* @param causedBy The throwable that caused the error.
|
||||
* @return A JSONException object, suitable for throwing
|
||||
*/
|
||||
public JSONException syntaxError(String message, Throwable causedBy) {
|
||||
return new JSONException(message + this.toString(), causedBy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a printable string of this JSONTokener.
|
||||
*
|
||||
* @return " at {index} [character {character} line {line}]"
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return " at " + this.index + " [character " + this.character + " line " +
|
||||
this.line + "]";
|
||||
}
|
||||
}
|
326
src/org/json/JSONWriter.java
Normal file
326
src/org/json/JSONWriter.java
Normal file
@ -0,0 +1,326 @@
|
||||
package org.json;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JSONWriter provides a quick and convenient way of producing JSON text.
|
||||
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||
* added, so the results are ready for transmission or storage. Each instance of
|
||||
* JSONWriter can produce one JSON text.
|
||||
* <p>
|
||||
* A JSONWriter instance provides a <code>value</code> method for appending
|
||||
* values to the
|
||||
* text, and a <code>key</code>
|
||||
* method for adding keys before values in objects. There are <code>array</code>
|
||||
* and <code>endArray</code> methods that make and bound array values, and
|
||||
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||
* object values. All of these methods return the JSONWriter instance,
|
||||
* permitting a cascade style. For example, <pre>
|
||||
* new JSONWriter(myWriter)
|
||||
* .object()
|
||||
* .key("JSON")
|
||||
* .value("Hello, World!")
|
||||
* .endObject();</pre> which writes <pre>
|
||||
* {"JSON":"Hello, World!"}</pre>
|
||||
* <p>
|
||||
* The first method called must be <code>array</code> or <code>object</code>.
|
||||
* There are no methods for adding commas or colons. JSONWriter adds them for
|
||||
* you. Objects and arrays can be nested up to 200 levels deep.
|
||||
* <p>
|
||||
* This can sometimes be easier than using a JSONObject to build a string.
|
||||
* @author JSON.org
|
||||
* @version 2016-08-08
|
||||
*/
|
||||
public class JSONWriter {
|
||||
private static final int maxdepth = 200;
|
||||
|
||||
/**
|
||||
* The comma flag determines if a comma should be output before the next
|
||||
* value.
|
||||
*/
|
||||
private boolean comma;
|
||||
|
||||
/**
|
||||
* The current mode. Values:
|
||||
* 'a' (array),
|
||||
* 'd' (done),
|
||||
* 'i' (initial),
|
||||
* 'k' (key),
|
||||
* 'o' (object).
|
||||
*/
|
||||
protected char mode;
|
||||
|
||||
/**
|
||||
* The object/array stack.
|
||||
*/
|
||||
private final JSONObject stack[];
|
||||
|
||||
/**
|
||||
* The stack top index. A value of 0 indicates that the stack is empty.
|
||||
*/
|
||||
private int top;
|
||||
|
||||
/**
|
||||
* The writer that will receive the output.
|
||||
*/
|
||||
protected Appendable writer;
|
||||
|
||||
/**
|
||||
* Make a fresh JSONWriter. It can be used to build one JSON text.
|
||||
*/
|
||||
public JSONWriter(Appendable w) {
|
||||
this.comma = false;
|
||||
this.mode = 'i';
|
||||
this.stack = new JSONObject[maxdepth];
|
||||
this.top = 0;
|
||||
this.writer = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a value.
|
||||
* @param string A string value.
|
||||
* @return this
|
||||
* @throws JSONException If the value is out of sequence.
|
||||
*/
|
||||
private JSONWriter append(String string) throws JSONException {
|
||||
if (string == null) {
|
||||
throw new JSONException("Null pointer");
|
||||
}
|
||||
if (this.mode == 'o' || this.mode == 'a') {
|
||||
try {
|
||||
if (this.comma && this.mode == 'a') {
|
||||
this.writer.append(',');
|
||||
}
|
||||
this.writer.append(string);
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
if (this.mode == 'o') {
|
||||
this.mode = 'k';
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Value out of sequence.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin appending a new array. All values until the balancing
|
||||
* <code>endArray</code> will be appended to this array. The
|
||||
* <code>endArray</code> method must be called to mark the array's end.
|
||||
* @return this
|
||||
* @throws JSONException If the nesting is too deep, or if the object is
|
||||
* started in the wrong place (for example as a key or after the end of the
|
||||
* outermost array or object).
|
||||
*/
|
||||
public JSONWriter array() throws JSONException {
|
||||
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
|
||||
this.push(null);
|
||||
this.append("[");
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced array.");
|
||||
}
|
||||
|
||||
/**
|
||||
* End something.
|
||||
* @param mode Mode
|
||||
* @param c Closing character
|
||||
* @return this
|
||||
* @throws JSONException If unbalanced.
|
||||
*/
|
||||
private JSONWriter end(char mode, char c) throws JSONException {
|
||||
if (this.mode != mode) {
|
||||
throw new JSONException(mode == 'a'
|
||||
? "Misplaced endArray."
|
||||
: "Misplaced endObject.");
|
||||
}
|
||||
this.pop(mode);
|
||||
try {
|
||||
this.writer.append(c);
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* End an array. This method most be called to balance calls to
|
||||
* <code>array</code>.
|
||||
* @return this
|
||||
* @throws JSONException If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endArray() throws JSONException {
|
||||
return this.end('a', ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* End an object. This method most be called to balance calls to
|
||||
* <code>object</code>.
|
||||
* @return this
|
||||
* @throws JSONException If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endObject() throws JSONException {
|
||||
return this.end('k', '}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a key. The key will be associated with the next value. In an
|
||||
* object, every value must be preceded by a key.
|
||||
* @param string A key string.
|
||||
* @return this
|
||||
* @throws JSONException If the key is out of place. For example, keys
|
||||
* do not belong in arrays or if the key is null.
|
||||
*/
|
||||
public JSONWriter key(String string) throws JSONException {
|
||||
if (string == null) {
|
||||
throw new JSONException("Null key.");
|
||||
}
|
||||
if (this.mode == 'k') {
|
||||
try {
|
||||
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
|
||||
if (this.comma) {
|
||||
this.writer.append(',');
|
||||
}
|
||||
this.writer.append(JSONObject.quote(string));
|
||||
this.writer.append(':');
|
||||
this.comma = false;
|
||||
this.mode = 'o';
|
||||
return this;
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
throw new JSONException("Misplaced key.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begin appending a new object. All keys and values until the balancing
|
||||
* <code>endObject</code> will be appended to this object. The
|
||||
* <code>endObject</code> method must be called to mark the object's end.
|
||||
* @return this
|
||||
* @throws JSONException If the nesting is too deep, or if the object is
|
||||
* started in the wrong place (for example as a key or after the end of the
|
||||
* outermost array or object).
|
||||
*/
|
||||
public JSONWriter object() throws JSONException {
|
||||
if (this.mode == 'i') {
|
||||
this.mode = 'o';
|
||||
}
|
||||
if (this.mode == 'o' || this.mode == 'a') {
|
||||
this.append("{");
|
||||
this.push(new JSONObject());
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced object.");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pop an array or object scope.
|
||||
* @param c The scope to close.
|
||||
* @throws JSONException If nesting is wrong.
|
||||
*/
|
||||
private void pop(char c) throws JSONException {
|
||||
if (this.top <= 0) {
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||
if (m != c) {
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
this.top -= 1;
|
||||
this.mode = this.top == 0
|
||||
? 'd'
|
||||
: this.stack[this.top - 1] == null
|
||||
? 'a'
|
||||
: 'k';
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an array or object scope.
|
||||
* @param jo The scope to open.
|
||||
* @throws JSONException If nesting is too deep.
|
||||
*/
|
||||
private void push(JSONObject jo) throws JSONException {
|
||||
if (this.top >= maxdepth) {
|
||||
throw new JSONException("Nesting too deep.");
|
||||
}
|
||||
this.stack[this.top] = jo;
|
||||
this.mode = jo == null ? 'a' : 'k';
|
||||
this.top += 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append either the value <code>true</code> or the value
|
||||
* <code>false</code>.
|
||||
* @param b A boolean.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(boolean b) throws JSONException {
|
||||
return this.append(b ? "true" : "false");
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double value.
|
||||
* @param d A double.
|
||||
* @return this
|
||||
* @throws JSONException If the number is not finite.
|
||||
*/
|
||||
public JSONWriter value(double d) throws JSONException {
|
||||
return this.value(new Double(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a long value.
|
||||
* @param l A long.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(long l) throws JSONException {
|
||||
return this.append(Long.toString(l));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append an object value.
|
||||
* @param object The object to append. It can be null, or a Boolean, Number,
|
||||
* String, JSONObject, or JSONArray, or an object that implements JSONString.
|
||||
* @return this
|
||||
* @throws JSONException If the value is out of sequence.
|
||||
*/
|
||||
public JSONWriter value(Object object) throws JSONException {
|
||||
return this.append(JSONObject.valueToString(object));
|
||||
}
|
||||
}
|
72
src/org/json/Property.java
Normal file
72
src/org/json/Property.java
Normal file
@ -0,0 +1,72 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Converts a Property file data into JSONObject and back.
|
||||
* @author JSON.org
|
||||
* @version 2015-05-05
|
||||
*/
|
||||
public class Property {
|
||||
/**
|
||||
* Converts a property file object into a JSONObject. The property file object is a table of name value pairs.
|
||||
* @param properties java.util.Properties
|
||||
* @return JSONObject
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
if (properties != null && !properties.isEmpty()) {
|
||||
Enumeration<?> enumProperties = properties.propertyNames();
|
||||
while(enumProperties.hasMoreElements()) {
|
||||
String name = (String)enumProperties.nextElement();
|
||||
jo.put(name, properties.getProperty(name));
|
||||
}
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the JSONObject into a property file object.
|
||||
* @param jo JSONObject
|
||||
* @return java.util.Properties
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static Properties toProperties(JSONObject jo) throws JSONException {
|
||||
Properties properties = new Properties();
|
||||
if (jo != null) {
|
||||
Iterator<String> keys = jo.keys();
|
||||
while (keys.hasNext()) {
|
||||
String name = keys.next();
|
||||
properties.put(name, jo.getString(name));
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
621
src/org/json/XML.java
Normal file
621
src/org/json/XML.java
Normal file
@ -0,0 +1,621 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2015 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This provides static methods to convert an XML text into a JSONObject, and to
|
||||
* covert a JSONObject into an XML text.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2016-08-10
|
||||
*/
|
||||
@SuppressWarnings("boxing")
|
||||
public class XML {
|
||||
/** The Character '&'. */
|
||||
public static final Character AMP = '&';
|
||||
|
||||
/** The Character '''. */
|
||||
public static final Character APOS = '\'';
|
||||
|
||||
/** The Character '!'. */
|
||||
public static final Character BANG = '!';
|
||||
|
||||
/** The Character '='. */
|
||||
public static final Character EQ = '=';
|
||||
|
||||
/** The Character '>'. */
|
||||
public static final Character GT = '>';
|
||||
|
||||
/** The Character '<'. */
|
||||
public static final Character LT = '<';
|
||||
|
||||
/** The Character '?'. */
|
||||
public static final Character QUEST = '?';
|
||||
|
||||
/** The Character '"'. */
|
||||
public static final Character QUOT = '"';
|
||||
|
||||
/** The Character '/'. */
|
||||
public static final Character SLASH = '/';
|
||||
|
||||
/**
|
||||
* Creates an iterator for navigating Code Points in a string instead of
|
||||
* characters. Once Java7 support is dropped, this can be replaced with
|
||||
* <code>
|
||||
* string.codePoints()
|
||||
* </code>
|
||||
* which is available in Java8 and above.
|
||||
*
|
||||
* @see <a href=
|
||||
* "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a>
|
||||
*/
|
||||
private static Iterable<Integer> codePointIterator(final String string) {
|
||||
return new Iterable<Integer>() {
|
||||
@Override
|
||||
public Iterator<Integer> iterator() {
|
||||
return new Iterator<Integer>() {
|
||||
private int nextIndex = 0;
|
||||
private int length = string.length();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.nextIndex < this.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer next() {
|
||||
int result = string.codePointAt(this.nextIndex);
|
||||
this.nextIndex += Character.charCount(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace special characters with XML escapes:
|
||||
*
|
||||
* <pre>
|
||||
* & <small>(ampersand)</small> is replaced by &amp;
|
||||
* < <small>(less than)</small> is replaced by &lt;
|
||||
* > <small>(greater than)</small> is replaced by &gt;
|
||||
* " <small>(double quote)</small> is replaced by &quot;
|
||||
* ' <small>(single quote / apostrophe)</small> is replaced by &apos;
|
||||
* </pre>
|
||||
*
|
||||
* @param string
|
||||
* The string to be escaped.
|
||||
* @return The escaped string.
|
||||
*/
|
||||
public static String escape(String string) {
|
||||
StringBuilder sb = new StringBuilder(string.length());
|
||||
for (final int cp : codePointIterator(string)) {
|
||||
switch (cp) {
|
||||
case '&':
|
||||
sb.append("&");
|
||||
break;
|
||||
case '<':
|
||||
sb.append("<");
|
||||
break;
|
||||
case '>':
|
||||
sb.append(">");
|
||||
break;
|
||||
case '"':
|
||||
sb.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
sb.append("'");
|
||||
break;
|
||||
default:
|
||||
if (mustEscape(cp)) {
|
||||
sb.append("&#x");
|
||||
sb.append(Integer.toHexString(cp));
|
||||
sb.append(";");
|
||||
} else {
|
||||
sb.appendCodePoint(cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cp code point to test
|
||||
* @return true if the code point is not valid for an XML
|
||||
*/
|
||||
private static boolean mustEscape(int cp) {
|
||||
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets
|
||||
*
|
||||
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
|
||||
*
|
||||
* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
|
||||
*/
|
||||
// isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F)
|
||||
// all ISO control characters are out of range except tabs and new lines
|
||||
return (Character.isISOControl(cp)
|
||||
&& cp != 0x9
|
||||
&& cp != 0xA
|
||||
&& cp != 0xD
|
||||
) || !(
|
||||
// valid the range of acceptable characters that aren't control
|
||||
(cp >= 0x20 && cp <= 0xD7FF)
|
||||
|| (cp >= 0xE000 && cp <= 0xFFFD)
|
||||
|| (cp >= 0x10000 && cp <= 0x10FFFF)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes XML escapes from the string.
|
||||
*
|
||||
* @param string
|
||||
* string to remove escapes from
|
||||
* @return string with converted entities
|
||||
*/
|
||||
public static String unescape(String string) {
|
||||
StringBuilder sb = new StringBuilder(string.length());
|
||||
for (int i = 0, length = string.length(); i < length; i++) {
|
||||
char c = string.charAt(i);
|
||||
if (c == '&') {
|
||||
final int semic = string.indexOf(';', i);
|
||||
if (semic > i) {
|
||||
final String entity = string.substring(i + 1, semic);
|
||||
if (entity.charAt(0) == '#') {
|
||||
int cp;
|
||||
if (entity.charAt(1) == 'x') {
|
||||
// hex encoded unicode
|
||||
cp = Integer.parseInt(entity.substring(2), 16);
|
||||
} else {
|
||||
// decimal encoded unicode
|
||||
cp = Integer.parseInt(entity.substring(1));
|
||||
}
|
||||
sb.appendCodePoint(cp);
|
||||
} else {
|
||||
if ("quot".equalsIgnoreCase(entity)) {
|
||||
sb.append('"');
|
||||
} else if ("amp".equalsIgnoreCase(entity)) {
|
||||
sb.append('&');
|
||||
} else if ("apos".equalsIgnoreCase(entity)) {
|
||||
sb.append('\'');
|
||||
} else if ("lt".equalsIgnoreCase(entity)) {
|
||||
sb.append('<');
|
||||
} else if ("gt".equalsIgnoreCase(entity)) {
|
||||
sb.append('>');
|
||||
} else {
|
||||
sb.append('&').append(entity).append(';');
|
||||
}
|
||||
}
|
||||
// skip past the entity we just parsed.
|
||||
i += entity.length() + 1;
|
||||
} else {
|
||||
// this shouldn't happen in most cases since the parser
|
||||
// errors on unclosed enties.
|
||||
sb.append(c);
|
||||
}
|
||||
} else {
|
||||
// not part of an entity
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if the string contains whitespace. Whitespace is not
|
||||
* allowed in tagNames and attributes.
|
||||
*
|
||||
* @param string
|
||||
* A string.
|
||||
* @throws JSONException Thrown if the string contains whitespace or is empty.
|
||||
*/
|
||||
public static void noSpace(String string) throws JSONException {
|
||||
int i, length = string.length();
|
||||
if (length == 0) {
|
||||
throw new JSONException("Empty string.");
|
||||
}
|
||||
for (i = 0; i < length; i += 1) {
|
||||
if (Character.isWhitespace(string.charAt(i))) {
|
||||
throw new JSONException("'" + string
|
||||
+ "' contains a space character.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the content following the named tag, attaching it to the context.
|
||||
*
|
||||
* @param x
|
||||
* The XMLTokener containing the source string.
|
||||
* @param context
|
||||
* The JSONObject that will include the new material.
|
||||
* @param name
|
||||
* The tag name.
|
||||
* @return true if the close tag is processed.
|
||||
* @throws JSONException
|
||||
*/
|
||||
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings)
|
||||
throws JSONException {
|
||||
char c;
|
||||
int i;
|
||||
JSONObject jsonobject = null;
|
||||
String string;
|
||||
String tagName;
|
||||
Object token;
|
||||
|
||||
// Test for and skip past these forms:
|
||||
// <!-- ... -->
|
||||
// <! ... >
|
||||
// <![ ... ]]>
|
||||
// <? ... ?>
|
||||
// Report errors for these forms:
|
||||
// <>
|
||||
// <=
|
||||
// <<
|
||||
|
||||
token = x.nextToken();
|
||||
|
||||
// <!
|
||||
|
||||
if (token == BANG) {
|
||||
c = x.next();
|
||||
if (c == '-') {
|
||||
if (x.next() == '-') {
|
||||
x.skipPast("-->");
|
||||
return false;
|
||||
}
|
||||
x.back();
|
||||
} else if (c == '[') {
|
||||
token = x.nextToken();
|
||||
if ("CDATA".equals(token)) {
|
||||
if (x.next() == '[') {
|
||||
string = x.nextCDATA();
|
||||
if (string.length() > 0) {
|
||||
context.accumulate("content", string);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
throw x.syntaxError("Expected 'CDATA['");
|
||||
}
|
||||
i = 1;
|
||||
do {
|
||||
token = x.nextMeta();
|
||||
if (token == null) {
|
||||
throw x.syntaxError("Missing '>' after '<!'.");
|
||||
} else if (token == LT) {
|
||||
i += 1;
|
||||
} else if (token == GT) {
|
||||
i -= 1;
|
||||
}
|
||||
} while (i > 0);
|
||||
return false;
|
||||
} else if (token == QUEST) {
|
||||
|
||||
// <?
|
||||
x.skipPast("?>");
|
||||
return false;
|
||||
} else if (token == SLASH) {
|
||||
|
||||
// Close tag </
|
||||
|
||||
token = x.nextToken();
|
||||
if (name == null) {
|
||||
throw x.syntaxError("Mismatched close tag " + token);
|
||||
}
|
||||
if (!token.equals(name)) {
|
||||
throw x.syntaxError("Mismatched " + name + " and " + token);
|
||||
}
|
||||
if (x.nextToken() != GT) {
|
||||
throw x.syntaxError("Misshaped close tag");
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (token instanceof Character) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
|
||||
// Open tag <
|
||||
|
||||
} else {
|
||||
tagName = (String) token;
|
||||
token = null;
|
||||
jsonobject = new JSONObject();
|
||||
for (;;) {
|
||||
if (token == null) {
|
||||
token = x.nextToken();
|
||||
}
|
||||
// attribute = value
|
||||
if (token instanceof String) {
|
||||
string = (String) token;
|
||||
token = x.nextToken();
|
||||
if (token == EQ) {
|
||||
token = x.nextToken();
|
||||
if (!(token instanceof String)) {
|
||||
throw x.syntaxError("Missing value");
|
||||
}
|
||||
jsonobject.accumulate(string,
|
||||
keepStrings ? unescape((String)token) : stringToValue((String) token));
|
||||
token = null;
|
||||
} else {
|
||||
jsonobject.accumulate(string, "");
|
||||
}
|
||||
|
||||
|
||||
} else if (token == SLASH) {
|
||||
// Empty tag <.../>
|
||||
if (x.nextToken() != GT) {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
if (jsonobject.length() > 0) {
|
||||
context.accumulate(tagName, jsonobject);
|
||||
} else {
|
||||
context.accumulate(tagName, "");
|
||||
}
|
||||
return false;
|
||||
|
||||
} else if (token == GT) {
|
||||
// Content, between <...> and </...>
|
||||
for (;;) {
|
||||
token = x.nextContent();
|
||||
if (token == null) {
|
||||
if (tagName != null) {
|
||||
throw x.syntaxError("Unclosed tag " + tagName);
|
||||
}
|
||||
return false;
|
||||
} else if (token instanceof String) {
|
||||
string = (String) token;
|
||||
if (string.length() > 0) {
|
||||
jsonobject.accumulate("content",
|
||||
keepStrings ? unescape(string) : stringToValue(string));
|
||||
}
|
||||
|
||||
} else if (token == LT) {
|
||||
// Nested element
|
||||
if (parse(x, jsonobject, tagName,keepStrings)) {
|
||||
if (jsonobject.length() == 0) {
|
||||
context.accumulate(tagName, "");
|
||||
} else if (jsonobject.length() == 1
|
||||
&& jsonobject.opt("content") != null) {
|
||||
context.accumulate(tagName,
|
||||
jsonobject.opt("content"));
|
||||
} else {
|
||||
context.accumulate(tagName, jsonobject);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw x.syntaxError("Misshaped tag");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is the same as {@link JSONObject.stringToValue(String)}
|
||||
* except that this also tries to unescape String values.
|
||||
*
|
||||
* @param string String to convert
|
||||
* @return JSON value of this string or the string
|
||||
*/
|
||||
public static Object stringToValue(String string) {
|
||||
Object ret = JSONObject.stringToValue(string);
|
||||
if(ret instanceof String){
|
||||
return unescape((String)ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject. Some information may be lost in this transformation because
|
||||
* JSON is a data format and XML is a document format. XML uses elements,
|
||||
* attributes, and content text, while JSON uses unordered collections of
|
||||
* name/value pairs and arrays of values. JSON does not does not like to
|
||||
* distinguish between elements and attributes. Sequences of similar
|
||||
* elements are represented as JSONArrays. Content text may be placed in a
|
||||
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code>
|
||||
* are ignored.
|
||||
*
|
||||
* @param string
|
||||
* The source string.
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown if there is an errors while parsing the string
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string) throws JSONException {
|
||||
return toJSONObject(string, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject. Some information may be lost in this transformation because
|
||||
* JSON is a data format and XML is a document format. XML uses elements,
|
||||
* attributes, and content text, while JSON uses unordered collections of
|
||||
* name/value pairs and arrays of values. JSON does not does not like to
|
||||
* distinguish between elements and attributes. Sequences of similar
|
||||
* elements are represented as JSONArrays. Content text may be placed in a
|
||||
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code>
|
||||
* are ignored.
|
||||
*
|
||||
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
|
||||
* numbers but will instead be the exact value as seen in the XML document.
|
||||
*
|
||||
* @param string
|
||||
* The source string.
|
||||
* @param keepStrings If true, then values will not be coerced into boolean
|
||||
* or numeric values and will instead be left as strings
|
||||
* @return A JSONObject containing the structured data from the XML string.
|
||||
* @throws JSONException Thrown if there is an errors while parsing the string
|
||||
*/
|
||||
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
XMLTokener x = new XMLTokener(string);
|
||||
while (x.more() && x.skipPast("<")) {
|
||||
parse(x, jo, null, keepStrings);
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
/**
|
||||
* Convert a JSONObject into a well-formed, element-normal XML string.
|
||||
*
|
||||
* @param object
|
||||
* A JSONObject.
|
||||
* @return A string.
|
||||
* @throws JSONException Thrown if there is an error parsing the string
|
||||
*/
|
||||
public static String toString(Object object) throws JSONException {
|
||||
return toString(object, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JSONObject into a well-formed, element-normal XML string.
|
||||
*
|
||||
* @param object
|
||||
* A JSONObject.
|
||||
* @param tagName
|
||||
* The optional name of the enclosing tag.
|
||||
* @return A string.
|
||||
* @throws JSONException Thrown if there is an error parsing the string
|
||||
*/
|
||||
public static String toString(Object object, String tagName)
|
||||
throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
JSONArray ja;
|
||||
JSONObject jo;
|
||||
String key;
|
||||
Iterator<String> keys;
|
||||
String string;
|
||||
Object value;
|
||||
|
||||
if (object instanceof JSONObject) {
|
||||
|
||||
// Emit <tagName>
|
||||
if (tagName != null) {
|
||||
sb.append('<');
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
|
||||
// Loop thru the keys.
|
||||
jo = (JSONObject) object;
|
||||
keys = jo.keys();
|
||||
while (keys.hasNext()) {
|
||||
key = keys.next();
|
||||
value = jo.opt(key);
|
||||
if (value == null) {
|
||||
value = "";
|
||||
} else if (value.getClass().isArray()) {
|
||||
value = new JSONArray(value);
|
||||
}
|
||||
string = value instanceof String ? (String) value : null;
|
||||
|
||||
// Emit content in body
|
||||
if ("content".equals(key)) {
|
||||
if (value instanceof JSONArray) {
|
||||
ja = (JSONArray) value;
|
||||
int i = 0;
|
||||
for (Object val : ja) {
|
||||
if (i > 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append(escape(val.toString()));
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
sb.append(escape(value.toString()));
|
||||
}
|
||||
|
||||
// Emit an array of similar keys
|
||||
|
||||
} else if (value instanceof JSONArray) {
|
||||
ja = (JSONArray) value;
|
||||
for (Object val : ja) {
|
||||
if (val instanceof JSONArray) {
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append('>');
|
||||
sb.append(toString(val));
|
||||
sb.append("</");
|
||||
sb.append(key);
|
||||
sb.append('>');
|
||||
} else {
|
||||
sb.append(toString(val, key));
|
||||
}
|
||||
}
|
||||
} else if ("".equals(value)) {
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append("/>");
|
||||
|
||||
// Emit a new tag <k>
|
||||
|
||||
} else {
|
||||
sb.append(toString(value, key));
|
||||
}
|
||||
}
|
||||
if (tagName != null) {
|
||||
|
||||
// Emit the </tagname> close tag
|
||||
sb.append("</");
|
||||
sb.append(tagName);
|
||||
sb.append('>');
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
if (object != null) {
|
||||
if (object.getClass().isArray()) {
|
||||
object = new JSONArray(object);
|
||||
}
|
||||
|
||||
if (object instanceof JSONArray) {
|
||||
ja = (JSONArray) object;
|
||||
for (Object val : ja) {
|
||||
// XML does not have good support for arrays. If an array
|
||||
// appears in a place where XML is lacking, synthesize an
|
||||
// <array> element.
|
||||
sb.append(toString(val, tagName == null ? "array" : tagName));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
string = (object == null) ? "null" : escape(object.toString());
|
||||
return (tagName == null) ? "\"" + string + "\""
|
||||
: (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName
|
||||
+ ">" + string + "</" + tagName + ">";
|
||||
|
||||
}
|
||||
}
|
365
src/org/json/XMLTokener.java
Normal file
365
src/org/json/XMLTokener.java
Normal file
@ -0,0 +1,365 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The XMLTokener extends the JSONTokener to provide additional methods
|
||||
* for the parsing of XML texts.
|
||||
* @author JSON.org
|
||||
* @version 2015-12-09
|
||||
*/
|
||||
public class XMLTokener extends JSONTokener {
|
||||
|
||||
|
||||
/** The table of entity values. It initially contains Character values for
|
||||
* amp, apos, gt, lt, quot.
|
||||
*/
|
||||
public static final java.util.HashMap<String, Character> entity;
|
||||
|
||||
static {
|
||||
entity = new java.util.HashMap<String, Character>(8);
|
||||
entity.put("amp", XML.AMP);
|
||||
entity.put("apos", XML.APOS);
|
||||
entity.put("gt", XML.GT);
|
||||
entity.put("lt", XML.LT);
|
||||
entity.put("quot", XML.QUOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an XMLTokener from a string.
|
||||
* @param s A source string.
|
||||
*/
|
||||
public XMLTokener(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text in the CDATA block.
|
||||
* @return The string up to the <code>]]></code>.
|
||||
* @throws JSONException If the <code>]]></code> is not found.
|
||||
*/
|
||||
public String nextCDATA() throws JSONException {
|
||||
char c;
|
||||
int i;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (end()) {
|
||||
throw syntaxError("Unclosed CDATA");
|
||||
}
|
||||
sb.append(c);
|
||||
i = sb.length() - 3;
|
||||
if (i >= 0 && sb.charAt(i) == ']' &&
|
||||
sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
|
||||
sb.setLength(i);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next XML outer token, trimming whitespace. There are two kinds
|
||||
* of tokens: the '<' character which begins a markup tag, and the content
|
||||
* text between markup tags.
|
||||
*
|
||||
* @return A string, or a '<' Character, or null if there is no more
|
||||
* source text.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public Object nextContent() throws JSONException {
|
||||
char c;
|
||||
StringBuilder sb;
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
if (c == 0) {
|
||||
return null;
|
||||
}
|
||||
if (c == '<') {
|
||||
return XML.LT;
|
||||
}
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
if (c == '<' || c == 0) {
|
||||
back();
|
||||
return sb.toString().trim();
|
||||
}
|
||||
if (c == '&') {
|
||||
sb.append(nextEntity(c));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
c = next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the next entity. These entities are translated to Characters:
|
||||
* <code>& ' > < "</code>.
|
||||
* @param ampersand An ampersand character.
|
||||
* @return A Character or an entity String if the entity is not recognized.
|
||||
* @throws JSONException If missing ';' in XML entity.
|
||||
*/
|
||||
public Object nextEntity(char ampersand) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (;;) {
|
||||
char c = next();
|
||||
if (Character.isLetterOrDigit(c) || c == '#') {
|
||||
sb.append(Character.toLowerCase(c));
|
||||
} else if (c == ';') {
|
||||
break;
|
||||
} else {
|
||||
throw syntaxError("Missing ';' in XML entity: &" + sb);
|
||||
}
|
||||
}
|
||||
String string = sb.toString();
|
||||
Object object = entity.get(string);
|
||||
return object != null ? object : ampersand + string + ";";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next XML meta token. This is used for skipping over <!...>
|
||||
* and <?...?> structures.
|
||||
* @return Syntax characters (<code>< > / = ! ?</code>) are returned as
|
||||
* Character, and strings and names are returned as Boolean. We don't care
|
||||
* what the values actually are.
|
||||
* @throws JSONException If a string is not properly closed or if the XML
|
||||
* is badly structured.
|
||||
*/
|
||||
public Object nextMeta() throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
switch (c) {
|
||||
case 0:
|
||||
throw syntaxError("Misshaped meta tag");
|
||||
case '<':
|
||||
return XML.LT;
|
||||
case '>':
|
||||
return XML.GT;
|
||||
case '/':
|
||||
return XML.SLASH;
|
||||
case '=':
|
||||
return XML.EQ;
|
||||
case '!':
|
||||
return XML.BANG;
|
||||
case '?':
|
||||
return XML.QUEST;
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
throw syntaxError("Unterminated string");
|
||||
}
|
||||
if (c == q) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
default:
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (Character.isWhitespace(c)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
switch (c) {
|
||||
case 0:
|
||||
case '<':
|
||||
case '>':
|
||||
case '/':
|
||||
case '=':
|
||||
case '!':
|
||||
case '?':
|
||||
case '"':
|
||||
case '\'':
|
||||
back();
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next XML Token. These tokens are found inside of angle
|
||||
* brackets. It may be one of these characters: <code>/ > = ! ?</code> or it
|
||||
* may be a string wrapped in single quotes or double quotes, or it may be a
|
||||
* name.
|
||||
* @return a String or a Character.
|
||||
* @throws JSONException If the XML is not well formed.
|
||||
*/
|
||||
public Object nextToken() throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
StringBuilder sb;
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
switch (c) {
|
||||
case 0:
|
||||
throw syntaxError("Misshaped element");
|
||||
case '<':
|
||||
throw syntaxError("Misplaced '<'");
|
||||
case '>':
|
||||
return XML.GT;
|
||||
case '/':
|
||||
return XML.SLASH;
|
||||
case '=':
|
||||
return XML.EQ;
|
||||
case '!':
|
||||
return XML.BANG;
|
||||
case '?':
|
||||
return XML.QUEST;
|
||||
|
||||
// Quoted string
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
throw syntaxError("Unterminated string");
|
||||
}
|
||||
if (c == q) {
|
||||
return sb.toString();
|
||||
}
|
||||
if (c == '&') {
|
||||
sb.append(nextEntity(c));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
||||
// Name
|
||||
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
sb.append(c);
|
||||
c = next();
|
||||
if (Character.isWhitespace(c)) {
|
||||
return sb.toString();
|
||||
}
|
||||
switch (c) {
|
||||
case 0:
|
||||
return sb.toString();
|
||||
case '>':
|
||||
case '/':
|
||||
case '=':
|
||||
case '!':
|
||||
case '?':
|
||||
case '[':
|
||||
case ']':
|
||||
back();
|
||||
return sb.toString();
|
||||
case '<':
|
||||
case '"':
|
||||
case '\'':
|
||||
throw syntaxError("Bad character in a name");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skip characters until past the requested string.
|
||||
* If it is not found, we are left at the end of the source with a result of false.
|
||||
* @param to A string to skip past.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public boolean skipPast(String to) throws JSONException {
|
||||
boolean b;
|
||||
char c;
|
||||
int i;
|
||||
int j;
|
||||
int offset = 0;
|
||||
int length = to.length();
|
||||
char[] circle = new char[length];
|
||||
|
||||
/*
|
||||
* First fill the circle buffer with as many characters as are in the
|
||||
* to string. If we reach an early end, bail.
|
||||
*/
|
||||
|
||||
for (i = 0; i < length; i += 1) {
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
return false;
|
||||
}
|
||||
circle[i] = c;
|
||||
}
|
||||
|
||||
/* We will loop, possibly for all of the remaining characters. */
|
||||
|
||||
for (;;) {
|
||||
j = offset;
|
||||
b = true;
|
||||
|
||||
/* Compare the circle buffer with the to string. */
|
||||
|
||||
for (i = 0; i < length; i += 1) {
|
||||
if (circle[j] != to.charAt(i)) {
|
||||
b = false;
|
||||
break;
|
||||
}
|
||||
j += 1;
|
||||
if (j >= length) {
|
||||
j -= length;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we exit the loop with b intact, then victory is ours. */
|
||||
|
||||
if (b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Get the next character. If there isn't one, then defeat is ours. */
|
||||
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Shove the character in the circle buffer and advance the
|
||||
* circle offset. The offset is mod n.
|
||||
*/
|
||||
circle[offset] = c;
|
||||
offset += 1;
|
||||
if (offset >= length) {
|
||||
offset -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
src/sig/CustomSound.java
Normal file
45
src/sig/CustomSound.java
Normal file
@ -0,0 +1,45 @@
|
||||
package sig;
|
||||
|
||||
|
||||
public class CustomSound {
|
||||
final static int SOUNDCOOLDOWN = 108000;
|
||||
private int cooldown = 0;
|
||||
private String customsound;
|
||||
private String username;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a <b>Custom Sound</b> object that will listen for a specific username.
|
||||
* @param username The username to listen for playing this sound.
|
||||
* @param customsound Just the filename of the custom sound. Not the absolute path.
|
||||
*/
|
||||
public CustomSound(String username, String customsound) {
|
||||
this.username=username;
|
||||
this.customsound=customsound;
|
||||
}
|
||||
|
||||
public boolean isSoundAvailable() {
|
||||
return cooldown<=0;
|
||||
}
|
||||
|
||||
public void decreaseCooldown(int amt) {
|
||||
cooldown-=amt;
|
||||
}
|
||||
|
||||
public void playCustomSound() {
|
||||
SoundUtils.playSound(sigIRC.BASEDIR+"sounds\\"+customsound);
|
||||
cooldown = SOUNDCOOLDOWN;
|
||||
}
|
||||
|
||||
public static CustomSound getCustomSound(String user) {
|
||||
for (CustomSound cs : sigIRC.customsounds) {
|
||||
if (cs.getUsername().equalsIgnoreCase(user)) {
|
||||
return cs;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
61
src/sig/DrawUtils.java
Normal file
61
src/sig/DrawUtils.java
Normal file
@ -0,0 +1,61 @@
|
||||
package sig;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.text.AttributedString;
|
||||
|
||||
public class DrawUtils {
|
||||
public static void drawOutlineText(Graphics g, Font font, double x, double y, int outline_size, Color text_color, Color shadow_color, String message) {
|
||||
AttributedString as = new AttributedString(message);
|
||||
as.addAttribute(TextAttribute.FONT, font);
|
||||
g.setColor(shadow_color);
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
if (message.length()>200) {
|
||||
g2.setColor(shadow_color);
|
||||
g2.drawString(as.getIterator(),(int)x+outline_size,(int)y+outline_size);
|
||||
} else {
|
||||
FontRenderContext frc = g2.getFontMetrics(font).getFontRenderContext();
|
||||
GlyphVector gv = font.createGlyphVector(frc, message);
|
||||
Rectangle2D box = gv.getVisualBounds();
|
||||
Shape shape = gv.getOutline((int)x,(int)y);
|
||||
g2.setClip(shape);
|
||||
g2.drawString(as.getIterator(),(int)x,(int)y);
|
||||
g2.setClip(null);
|
||||
g2.setStroke(new BasicStroke(outline_size*2));
|
||||
g2.setColor(shadow_color);
|
||||
g2.setRenderingHint(
|
||||
RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.draw(shape);
|
||||
}
|
||||
g2.setColor(text_color);
|
||||
g2.drawString(as.getIterator(),(int)x,(int)y);
|
||||
}
|
||||
public static void drawText(Graphics g, double x, double y, Color color, String message) {
|
||||
AttributedString as = new AttributedString(message);
|
||||
as.addAttribute(TextAttribute.FONT, MyPanel.programFont);
|
||||
g.setColor(color);
|
||||
g.drawString(as.getIterator(),(int)x,(int)y);
|
||||
}
|
||||
public static void drawTextFont(Graphics g, Font font, double x, double y, Color color, String message) {
|
||||
AttributedString as = new AttributedString(message);
|
||||
as.addAttribute(TextAttribute.FONT, font);
|
||||
g.setColor(color);
|
||||
g.drawString(as.getIterator(),(int)x,(int)y);
|
||||
}
|
||||
public static void drawHealthbar(Graphics g, Rectangle bounds, double pct, Color healthbarcol) {
|
||||
g.setColor(Color.BLACK);
|
||||
g.draw3DRect((int)bounds.getX(), (int)bounds.getY(), (int)bounds.getWidth(), (int)bounds.getHeight(), true);
|
||||
g.setColor(healthbarcol);
|
||||
g.fill3DRect((int)bounds.getX()+1, (int)bounds.getY()+1, (int)(bounds.getWidth()*pct)-1, (int)bounds.getHeight()-1, true);
|
||||
}
|
||||
}
|
75
src/sig/Emoticon.java
Normal file
75
src/sig/Emoticon.java
Normal file
@ -0,0 +1,75 @@
|
||||
package sig;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class Emoticon {
|
||||
private BufferedImage image=null;
|
||||
private String emotename=null;
|
||||
private String spacefiller="";
|
||||
|
||||
public Emoticon(String emoteName, URL onlinePath) {
|
||||
try {
|
||||
String imagePath = sigIRC.BASEDIR+"Emotes\\"+emoteName+".png";
|
||||
File file = new File(imagePath);
|
||||
if (file.exists()) {
|
||||
image = ImageIO.read(file);
|
||||
emotename = file.getName();
|
||||
} else {
|
||||
//Download it from online.
|
||||
System.out.println("Could not find emote "+emoteName+". Downloading from server...");
|
||||
image = ImageIO.read(onlinePath);
|
||||
System.out.println("Downloaded "+emoteName+".png");
|
||||
ImageIO.write(image, "png", file);
|
||||
System.out.println("Saved to "+file.getName()+".");
|
||||
emotename = emoteName;
|
||||
}
|
||||
spacefiller = GetSpaceLength();
|
||||
//System.out.println("Space size for "+emotename+" is "+spacefiller.length());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Emoticon(String emoteName, String fileName) {
|
||||
try {
|
||||
String imagePath = sigIRC.BASEDIR+"Emotes\\"+fileName+".png";
|
||||
File file = new File(imagePath);
|
||||
if (file.exists()) {
|
||||
image = ImageIO.read(file);
|
||||
emotename = emoteName;
|
||||
}
|
||||
spacefiller = GetSpaceLength();
|
||||
//System.out.println("Space size for "+emotename+" is "+spacefiller.length());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String GetSpaceLength() {
|
||||
StringBuilder spaces = new StringBuilder();
|
||||
while (SpaceFilledIsSmallerThanImageWidth(spaces)) {
|
||||
spaces.append(" ");
|
||||
}
|
||||
return spaces.toString();
|
||||
}
|
||||
|
||||
public boolean SpaceFilledIsSmallerThanImageWidth(StringBuilder spaces) {
|
||||
return TextUtils.calculateStringBoundsFont(spaces.toString(), sigIRC.panel.programFont).getWidth()<image.getWidth();
|
||||
}
|
||||
|
||||
public String getEmoteName() {
|
||||
return emotename.replace(".png", "");
|
||||
}
|
||||
|
||||
public BufferedImage getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public String getSpaceFiller() {
|
||||
return spacefiller;
|
||||
}
|
||||
}
|
105
src/sig/FileUtils.java
Normal file
105
src/sig/FileUtils.java
Normal file
@ -0,0 +1,105 @@
|
||||
package sig;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class FileUtils {
|
||||
public static String[] readFromFile(String filename) {
|
||||
File file = new File(filename);
|
||||
//System.out.println(file.getAbsolutePath());
|
||||
List<String> contents= new ArrayList<String>();
|
||||
if (file.exists()) {
|
||||
try(
|
||||
FileReader fw = new FileReader(filename);
|
||||
BufferedReader bw = new BufferedReader(fw);)
|
||||
{
|
||||
String readline = bw.readLine();
|
||||
do {
|
||||
if (readline!=null) {
|
||||
//System.out.println(readline);
|
||||
contents.add(readline);
|
||||
readline = bw.readLine();
|
||||
}} while (readline!=null);
|
||||
fw.close();
|
||||
bw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return contents.toArray(new String[contents.size()]);
|
||||
}
|
||||
|
||||
private static String readAll(Reader rd) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int cp;
|
||||
while ((cp = rd.read()) != -1) {
|
||||
sb.append((char) cp);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
|
||||
InputStream is = new URL(url).openStream();
|
||||
try {
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||
String jsonText = readAll(rd);
|
||||
JSONObject json = new JSONObject(jsonText);
|
||||
return json;
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void logToFile(String message, String filename) {
|
||||
File file = new File(filename);
|
||||
try {
|
||||
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
FileWriter fw = new FileWriter(file, true);
|
||||
PrintWriter pw = new PrintWriter(fw);
|
||||
|
||||
pw.println(message);
|
||||
pw.flush();
|
||||
pw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void writetoFile(String[] data, String filename) {
|
||||
File file = new File(filename);
|
||||
try {
|
||||
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
FileWriter fw = new FileWriter(file,false);
|
||||
PrintWriter pw = new PrintWriter(fw);
|
||||
|
||||
for (String s : data) {
|
||||
pw.println(s);
|
||||
}
|
||||
pw.flush();
|
||||
pw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
36
src/sig/Module.java
Normal file
36
src/sig/Module.java
Normal file
@ -0,0 +1,36 @@
|
||||
package sig;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
public class Module {
|
||||
protected Rectangle2D bounds;
|
||||
protected boolean enabled;
|
||||
protected String name;
|
||||
|
||||
public Module(Rectangle2D bounds, String moduleName) {
|
||||
this.bounds = bounds;
|
||||
this.name = moduleName;
|
||||
this.enabled=true;
|
||||
}
|
||||
|
||||
public Module(Rectangle2D bounds, String moduleName, boolean enabled) {
|
||||
this.bounds = bounds;
|
||||
this.name = moduleName;
|
||||
this.enabled=enabled;
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent ev) {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
}
|
||||
|
||||
public void draw(Graphics g) {
|
||||
sigIRC.panel.repaint(bounds.getBounds());
|
||||
}
|
||||
|
||||
public void mouseWheel(MouseWheelEvent ev) {
|
||||
}
|
||||
}
|
88
src/sig/MyPanel.java
Normal file
88
src/sig/MyPanel.java
Normal file
@ -0,0 +1,88 @@
|
||||
package sig;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
public class MyPanel extends JPanel implements MouseListener, ActionListener, MouseWheelListener{
|
||||
//List<String> messages = new ArrayList<String>();
|
||||
final public static Font programFont = new Font("Gill Sans Ultra Bold Condensed",0,24);
|
||||
final public static Font userFont = new Font("Gill Sans",0,16);
|
||||
final public static Font smallFont = new Font("Agency FB Bold",0,12);
|
||||
|
||||
public MyPanel() {
|
||||
//setBorder(BorderFactory.createLineBorder(Color.black));
|
||||
addMouseListener(this);
|
||||
addMouseWheelListener(this);
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(1280,480);
|
||||
}
|
||||
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
// Draw Text
|
||||
//int counter=18;
|
||||
for (TwitchEmote e : sigIRC.twitchemoticons) {
|
||||
e.draw(g);
|
||||
}
|
||||
for (ScrollingText st : sigIRC.textobj) {
|
||||
st.draw(g);
|
||||
}
|
||||
for (Module m : sigIRC.modules) {
|
||||
m.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
public void addMessage(String message) {
|
||||
ScrollingText text = new ScrollingText(message,this.getWidth(),(int)(Math.random()*128),sigIRC.TEXTSCROLLSPD);
|
||||
TextRow row = TextRow.PickRandomTextRow(text.getUsername());
|
||||
sigIRC.textobj.add(text);
|
||||
row.updateRow(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent ev) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent ev) {
|
||||
for (Module m : sigIRC.modules) {
|
||||
m.mousePressed(ev);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent ev) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent ev) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent ev) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent ev) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseWheelEvent ev) {
|
||||
for (Module m : sigIRC.modules) {
|
||||
m.mouseWheel(ev);
|
||||
}
|
||||
}
|
||||
}
|
232
src/sig/ScrollingText.java
Normal file
232
src/sig/ScrollingText.java
Normal file
@ -0,0 +1,232 @@
|
||||
package sig;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
public class ScrollingText {
|
||||
private String username;
|
||||
private String message;
|
||||
private double x;
|
||||
private double y;
|
||||
private double scrollspd;
|
||||
private int stringWidth;
|
||||
private int stringHeight;
|
||||
private boolean isAlive=true;
|
||||
private Color userColor;
|
||||
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public int getStringWidth() {
|
||||
return stringWidth;
|
||||
}
|
||||
|
||||
public int getStringHeight() {
|
||||
return stringHeight;
|
||||
}
|
||||
|
||||
private int userstringWidth;
|
||||
private int shadowSize;
|
||||
|
||||
public ScrollingText(String msg, double x, double y, double scrollspd) {
|
||||
LogMessageToFile(msg);
|
||||
this.username = GetUsername(msg);
|
||||
this.userColor = GetUserNameColor(this.username);
|
||||
this.message = GetMessage(msg);
|
||||
this.x=x;
|
||||
this.y=y;
|
||||
this.scrollspd=scrollspd;
|
||||
|
||||
this.shadowSize=2;
|
||||
|
||||
this.stringWidth = (int)TextUtils.calculateStringBoundsFont(this.message,MyPanel.programFont).getWidth();
|
||||
this.stringHeight = (int)TextUtils.calculateStringBoundsFont(this.message,MyPanel.programFont).getHeight();
|
||||
this.userstringWidth = (int)TextUtils.calculateStringBoundsFont(this.username,MyPanel.userFont).getWidth();
|
||||
|
||||
playMessageSound(username);
|
||||
}
|
||||
|
||||
private void playMessageSound(String user) {
|
||||
CustomSound cs = CustomSound.getCustomSound(user);
|
||||
if (cs!=null && cs.isSoundAvailable()) {
|
||||
cs.playCustomSound();
|
||||
} else {
|
||||
String soundName = sigIRC.BASEDIR+"sounds\\ping.wav";
|
||||
SoundUtils.playSound(soundName);
|
||||
}
|
||||
}
|
||||
|
||||
private void LogMessageToFile(String message) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
FileUtils.logToFile(message, sigIRC.BASEDIR+"logs\\log_"+(cal.get(Calendar.MONTH)+1)+"_"+cal.get(Calendar.DAY_OF_MONTH)+"_"+cal.get(Calendar.YEAR)+".txt");
|
||||
}
|
||||
|
||||
private Color GetUserNameColor(String username) {
|
||||
Random r = new Random();
|
||||
r.setSeed(username.hashCode());
|
||||
int randomnumb = r.nextInt(3);
|
||||
Color col;
|
||||
switch (randomnumb) {
|
||||
case 0:{
|
||||
col=new Color(255,r.nextInt(128)+64,r.nextInt(128)+64,255);
|
||||
}break;
|
||||
case 1:{
|
||||
col=new Color(r.nextInt(128)+64,255,r.nextInt(128)+64,255);
|
||||
}break;
|
||||
case 2:{
|
||||
col=new Color(r.nextInt(128)+64,r.nextInt(128)+64,255,255);
|
||||
}break;
|
||||
default:{
|
||||
col=Color.GREEN;
|
||||
}
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
public boolean run() {
|
||||
x-=scrollspd;
|
||||
//System.out.println("X: "+x);
|
||||
sigIRC.panel.repaint(
|
||||
FindLeftMostCornerInDisplay(),
|
||||
FindTopMostCornerInDisplay()-32,
|
||||
(int)Math.max(FindRightMostCornerInDisplay(),(int)TextUtils.calculateStringBoundsFont(username, MyPanel.userFont).getWidth())+4,
|
||||
FindBottomMostCornerInDisplay()+(stringHeight*2)+4);
|
||||
//sigIRC.panel.repaint();
|
||||
if (x+stringWidth<0) {
|
||||
isAlive=false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void draw(Graphics g) {
|
||||
if (isAlive) {
|
||||
//DrawUtils.drawTextFont(g, MyPanel.userFont, x+8, y+stringHeight-20, Color.GREEN, username);
|
||||
DrawUtils.drawOutlineText(g, MyPanel.userFont, x+8, y+stringHeight-20, 2, userColor, Color.BLACK, username);
|
||||
DrawUtils.drawOutlineText(g, MyPanel.programFont, x, y+stringHeight, 2, Color.WHITE, Color.BLACK, message);
|
||||
}
|
||||
}
|
||||
|
||||
public int FindLeftMostCornerInDisplay() {
|
||||
if (x-shadowSize>0) {
|
||||
return Math.min((int)x-shadowSize, sigIRC.panel.getWidth());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public int FindTopMostCornerInDisplay() {
|
||||
if (y-shadowSize>0) {
|
||||
return Math.min((int)y-shadowSize, sigIRC.panel.getHeight());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public int FindRightMostCornerInDisplay() {
|
||||
if (x+stringWidth+(int)scrollspd+1+shadowSize+1>0) {
|
||||
return Math.min(Math.max(stringWidth,userstringWidth+8)+(int)scrollspd+1+shadowSize+1, sigIRC.panel.getWidth()-(int)x);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public int FindBottomMostCornerInDisplay() {
|
||||
if (y+stringHeight+shadowSize>0) {
|
||||
return Math.min(stringHeight+shadowSize+4, sigIRC.panel.getHeight()-(int)y);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private String GetMessage(String msg) {
|
||||
String basemsg = " "+msg.substring(msg.indexOf(":")+2, msg.length())+" ";
|
||||
//basemsg = ConvertMessageSymbols(basemsg);
|
||||
basemsg = ReplaceMessageWithEmoticons(basemsg);
|
||||
return basemsg.replaceFirst(" ", "").substring(0,basemsg.length()-1);
|
||||
}
|
||||
|
||||
private String ConvertMessageSymbols(String basemsg) {
|
||||
basemsg = basemsg.replace("/", "SLASH").replace(":", "COLON").replace("\\", "BACKSLASH").replace("|", "BAR").replace(">", "GREATERTHAN").replace("<", "LESSTHAN");
|
||||
return basemsg;
|
||||
}
|
||||
|
||||
private String ReplaceMessageWithEmoticons(String basemsg) {
|
||||
int marker = basemsg.indexOf(" ");
|
||||
while (marker<basemsg.length()) {
|
||||
//Find a space.
|
||||
int space = basemsg.indexOf(" ", marker+1);
|
||||
if (space>0) {
|
||||
String word = basemsg.substring(marker+1, space);
|
||||
//System.out.println("Word is '"+word+"'");
|
||||
|
||||
for (Emoticon e : sigIRC.emoticons) {
|
||||
if (e.getEmoteName().equalsIgnoreCase(word)) {
|
||||
basemsg = TextUtils.replaceFirst(basemsg, e.getEmoteName(), e.getSpaceFiller());
|
||||
GenerateEmoticon(marker+1, basemsg, e);
|
||||
space = basemsg.indexOf(" ", marker+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
marker=space;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return basemsg;
|
||||
}
|
||||
|
||||
private boolean EmoteExists(Emoticon e, String basemsg) {
|
||||
//Emote exists if it is standalone (no other words in message),
|
||||
//Contains spaces on both sides,
|
||||
//OR contains spaces in front/behind and ends the message with the emote.
|
||||
String tempstr = " "+basemsg+" ";
|
||||
return tempstr.contains(" "+e.getEmoteName()+" ");
|
||||
}
|
||||
|
||||
private void GenerateEmoticon(int pos, String basemsg, Emoticon e) {
|
||||
String cutstring = basemsg.substring(0, pos);
|
||||
double width = TextUtils.calculateStringBoundsFont(cutstring, sigIRC.panel.programFont).getWidth();
|
||||
//System.out.println("Width of '"+cutstring+"' is "+width);
|
||||
sigIRC.createEmoticon(e, this, (int)(width), 0);
|
||||
}
|
||||
|
||||
private String GetUsername(String msg) {
|
||||
return msg.substring(0,msg.indexOf(":"));
|
||||
}
|
||||
}
|
30
src/sig/SoundUtils.java
Normal file
30
src/sig/SoundUtils.java
Normal file
@ -0,0 +1,30 @@
|
||||
package sig;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
public class SoundUtils {
|
||||
public static void playSound(String filename) {
|
||||
AudioInputStream audioInputStream;
|
||||
try {
|
||||
audioInputStream = AudioSystem.getAudioInputStream(new File(filename).getAbsoluteFile());
|
||||
Clip clip;
|
||||
try {
|
||||
clip = AudioSystem.getClip();
|
||||
clip.open(audioInputStream);
|
||||
clip.start();
|
||||
} catch (LineUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (UnsupportedAudioFileException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
43
src/sig/TextRow.java
Normal file
43
src/sig/TextRow.java
Normal file
@ -0,0 +1,43 @@
|
||||
package sig;
|
||||
import java.util.Random;
|
||||
|
||||
public class TextRow {
|
||||
private int maxX = 0; //Defines the greatest X position of all the messages in this row.
|
||||
private int ypos = 0;
|
||||
final int MESSAGE_SEPARATION=200;
|
||||
|
||||
public TextRow(int ypos) {
|
||||
this.ypos=ypos;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return ypos;
|
||||
}
|
||||
|
||||
public void setY(int ypos) {
|
||||
this.ypos = ypos;
|
||||
}
|
||||
|
||||
public int getMaxX() {
|
||||
return maxX;
|
||||
}
|
||||
|
||||
public void updateRow(ScrollingText text) {
|
||||
text.setX(maxX+sigIRC.panel.getWidth()+MESSAGE_SEPARATION);
|
||||
text.setY(ypos);
|
||||
maxX+=text.getStringWidth()+MESSAGE_SEPARATION;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (maxX>0) {
|
||||
maxX-=sigIRC.TEXTSCROLLSPD;
|
||||
}
|
||||
}
|
||||
|
||||
public static TextRow PickRandomTextRow(String username) {
|
||||
Random r = new Random();
|
||||
r.setSeed(username.hashCode());
|
||||
int randomnumb = r.nextInt(sigIRC.rowobj.size());
|
||||
return sigIRC.rowobj.get(randomnumb);
|
||||
}
|
||||
}
|
70
src/sig/TextUtils.java
Normal file
70
src/sig/TextUtils.java
Normal file
@ -0,0 +1,70 @@
|
||||
package sig;
|
||||
import java.awt.Font;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
public class TextUtils {
|
||||
|
||||
public static Rectangle2D calculateStringBoundsFont(String msg, Font font) {
|
||||
FontRenderContext frc = sigIRC.panel.getFontMetrics(font).getFontRenderContext();
|
||||
return font.getStringBounds(msg, frc);
|
||||
}
|
||||
|
||||
public static String replaceFirst(String sourcestring, String findstring, String replacestring) {
|
||||
int pos = sourcestring.indexOf(findstring);
|
||||
if (pos>=0) {
|
||||
String piece1 = sourcestring.substring(0,pos);
|
||||
String piece2 = sourcestring.substring(pos+findstring.length(),sourcestring.length());
|
||||
//basemsg = basemsg.replaceFirst(e.getEmoteName(),e.getSpaceFiller());
|
||||
sourcestring = piece1+replacestring+piece2;
|
||||
}
|
||||
return sourcestring;
|
||||
}
|
||||
|
||||
public static boolean isNumeric(String str)
|
||||
{
|
||||
return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
|
||||
}
|
||||
|
||||
public static boolean isInteger(String s, int radix) {
|
||||
if(s.isEmpty()) return false;
|
||||
for(int i = 0; i < s.length(); i++) {
|
||||
if(i == 0 && s.charAt(i) == '-') {
|
||||
if(s.length() == 1) return false;
|
||||
else continue;
|
||||
}
|
||||
if(Character.digit(s.charAt(i),radix) < 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String convertSecondsToTimeFormat(int seconds) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int sec = seconds%60;
|
||||
int min = (seconds/60)%60;
|
||||
int hrs = (min/60)%60;
|
||||
if (hrs>0) {
|
||||
if (hrs>=10) {
|
||||
sb.append(hrs);
|
||||
} else {
|
||||
sb.append(0);
|
||||
sb.append(hrs);
|
||||
}
|
||||
sb.append(":");
|
||||
}
|
||||
if (min>=10) {
|
||||
sb.append(min);
|
||||
} else {
|
||||
sb.append(0);
|
||||
sb.append(min);
|
||||
}
|
||||
sb.append(":");
|
||||
if (sec>=10) {
|
||||
sb.append(sec);
|
||||
} else {
|
||||
sb.append(0);
|
||||
sb.append(sec);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
34
src/sig/TwitchEmote.java
Normal file
34
src/sig/TwitchEmote.java
Normal file
@ -0,0 +1,34 @@
|
||||
package sig;
|
||||
import java.awt.Graphics;
|
||||
|
||||
public class TwitchEmote {
|
||||
Emoticon emote;
|
||||
int x=0; //X Offset
|
||||
int y=0; //Y Offset
|
||||
ScrollingText text;
|
||||
|
||||
public TwitchEmote(Emoticon emote, ScrollingText textref, int x, int y) {
|
||||
this.emote=emote;
|
||||
this.x=x;
|
||||
this.y=y+32-emote.getImage().getHeight();
|
||||
this.text = textref;
|
||||
}
|
||||
|
||||
public boolean run() {
|
||||
//this.x-=paint.TEXTSCROLLSPD;
|
||||
sigIRC.panel.repaint(
|
||||
Math.max(x,0),
|
||||
Math.max(y, 0),
|
||||
Math.min(sigIRC.panel.getWidth()-x,emote.getImage().getWidth())+1,
|
||||
Math.min(sigIRC.panel.getHeight()-y,emote.getImage().getHeight())+1);
|
||||
if (x+emote.getImage().getWidth()<0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Graphics g) {
|
||||
g.drawImage(emote.getImage(), (int)(text.getX()+x), (int)(text.getY()+y), sigIRC.panel);
|
||||
}
|
||||
}
|
36
src/sig/UpdateEvent.java
Normal file
36
src/sig/UpdateEvent.java
Normal file
@ -0,0 +1,36 @@
|
||||
package sig;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class UpdateEvent implements ActionListener{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent ev) {
|
||||
UpdateScrollingText();
|
||||
}
|
||||
|
||||
public void UpdateScrollingText() {
|
||||
for (int i=0;i<sigIRC.twitchemoticons.size();i++) {
|
||||
boolean keep = sigIRC.twitchemoticons.get(i).run();
|
||||
if (!keep) {
|
||||
sigIRC.twitchemoticons.remove(i--);
|
||||
}
|
||||
}
|
||||
for (int i=0;i<sigIRC.textobj.size();i++) {
|
||||
boolean keep = sigIRC.textobj.get(i).run();
|
||||
if (!keep) {
|
||||
sigIRC.textobj.remove(i--);
|
||||
}
|
||||
}
|
||||
for (TextRow tr : sigIRC.rowobj) {
|
||||
tr.update();
|
||||
}
|
||||
for (CustomSound cs : sigIRC.customsounds) {
|
||||
if (!cs.isSoundAvailable()) {
|
||||
cs.decreaseCooldown(1);
|
||||
}
|
||||
}
|
||||
for (Module m : sigIRC.modules) {
|
||||
m.run();
|
||||
}
|
||||
}
|
||||
}
|
82
src/sig/modules/TouhouMother/Button.java
Normal file
82
src/sig/modules/TouhouMother/Button.java
Normal file
@ -0,0 +1,82 @@
|
||||
package sig.modules.TouhouMother;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import sig.DrawUtils;
|
||||
import sig.FileUtils;
|
||||
import sig.TextUtils;
|
||||
import sig.sigIRC;
|
||||
import sig.modules.TouhouMotherModule;
|
||||
|
||||
public class Button {
|
||||
BufferedImage buttonimg;
|
||||
int x=0;
|
||||
int y=0;
|
||||
String[] data;
|
||||
int currentselection=4;
|
||||
TouhouMotherModule module;
|
||||
|
||||
public Button(TouhouMotherModule parentmodule, File filename, int x, int y) {
|
||||
this.x=x;
|
||||
this.y=y;
|
||||
data = FileUtils.readFromFile(sigIRC.BASEDIR+"..\\WSplits");
|
||||
this.module=parentmodule;
|
||||
try {
|
||||
buttonimg = ImageIO.read(filename);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Graphics g) {
|
||||
DrawUtils.drawOutlineText(g, sigIRC.panel.smallFont, x-TextUtils.calculateStringBoundsFont(data[currentselection].split(",")[0], sigIRC.panel.smallFont).getWidth(), (int)module.getBounds().getY()+(int)module.getBounds().getHeight()-8, 1, Color.BLACK, Color.WHITE,
|
||||
data[currentselection].split(",")[0]);
|
||||
g.drawImage(buttonimg, x, y, sigIRC.panel);
|
||||
}
|
||||
|
||||
public void onClickEvent(MouseEvent ev) {
|
||||
if (ev.getX()>=x && ev.getX()<=x+buttonimg.getWidth() &&
|
||||
ev.getY()>=y && ev.getY()<=y+buttonimg.getHeight()) {
|
||||
for (int i=4;i<=currentselection;i++) {
|
||||
int runCount = Integer.parseInt(data[i].substring(data[i].indexOf("(")+1, data[i].indexOf(")")));
|
||||
data[i]=data[i].replace("("+Integer.toString(runCount)+")", "("+Integer.toString(++runCount)+")");
|
||||
}
|
||||
FileUtils.writetoFile(data, sigIRC.BASEDIR+"..\\WSplits");
|
||||
}
|
||||
}
|
||||
|
||||
public void onMouseWheelEvent(MouseWheelEvent ev) {
|
||||
int nextselection = currentselection+(int)Math.signum(ev.getWheelRotation());
|
||||
nextselection = LoopSelectionAround(nextselection);
|
||||
currentselection=nextselection;
|
||||
}
|
||||
|
||||
public int LoopSelectionAround(int nextselection) {
|
||||
if (nextselection<4) {
|
||||
nextselection=findLastNonBlankLine();
|
||||
} else
|
||||
if (nextselection>=findLastNonBlankLine()) {
|
||||
nextselection=4;
|
||||
}
|
||||
return nextselection;
|
||||
}
|
||||
|
||||
private int findLastNonBlankLine() {
|
||||
for (int i=data.length-2;i>=0;i++) {
|
||||
if (data[i].length()>0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
System.out.println("WARNING! Could not find last non blank line!");
|
||||
return -1;
|
||||
}
|
||||
}
|
34
src/sig/modules/TouhouMother/DataProperty.java
Normal file
34
src/sig/modules/TouhouMother/DataProperty.java
Normal file
@ -0,0 +1,34 @@
|
||||
package sig.modules.TouhouMother;
|
||||
|
||||
public enum DataProperty {
|
||||
CURRENTDAMAGE(0,"Last Battle"),
|
||||
TOTALDAMAGE(1,"Total Damage"),
|
||||
DAMAGETURNS(2,"Damage Turns"),
|
||||
LARGESTHIT(3,"Largest Hit");
|
||||
|
||||
private int id;
|
||||
private String displayname;
|
||||
|
||||
DataProperty(int id, String displayname) {
|
||||
this.id=id;
|
||||
this.displayname=displayname;
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayname;
|
||||
}
|
||||
|
||||
public static DataProperty getDataPropertyBasedOnID(int id) {
|
||||
for (DataProperty dp : DataProperty.values()) {
|
||||
if (dp.getID()==id) {
|
||||
return dp;
|
||||
}
|
||||
}
|
||||
System.out.println("Warning! Could not find Data Property with ID "+id+"!");
|
||||
return CURRENTDAMAGE;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package sig.modules.TouhouMother;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import sig.modules.TouhouMotherModule;
|
||||
|
||||
public class IncreaseTouhouMotherClockCount implements ActionListener{
|
||||
TouhouMotherModule tmm;
|
||||
public IncreaseTouhouMotherClockCount(TouhouMotherModule touhouMotherModule) {
|
||||
this.tmm=touhouMotherModule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent ev) {
|
||||
tmm.secondsCount++;
|
||||
}
|
||||
}
|
77
src/sig/modules/TouhouMother/TimeRecord.java
Normal file
77
src/sig/modules/TouhouMother/TimeRecord.java
Normal file
@ -0,0 +1,77 @@
|
||||
package sig.modules.TouhouMother;
|
||||
|
||||
import sig.FileUtils;
|
||||
import sig.sigIRC;
|
||||
import sig.modules.TouhouMotherModule;
|
||||
|
||||
public class TimeRecord {
|
||||
final public static int ERROR_VALUE = Integer.MAX_VALUE;
|
||||
public static TouhouMotherModule tmm;
|
||||
private int boss_id;
|
||||
private int seconds;
|
||||
|
||||
public TimeRecord(int id, int seconds) {
|
||||
this.boss_id=id;
|
||||
this.seconds=seconds;
|
||||
}
|
||||
|
||||
public static void LoadRecordDatabase() {
|
||||
String[] records = FileUtils.readFromFile(sigIRC.BASEDIR+"records");
|
||||
for (String s : records) {
|
||||
if (s.contains(":")) {
|
||||
String[] pieces = s.split(":");
|
||||
tmm.recordDatabase.add(new TimeRecord(
|
||||
Integer.parseInt(pieces[0]),
|
||||
Integer.parseInt(pieces[1])
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveRecordDatabase() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (TimeRecord tr : tmm.recordDatabase) {
|
||||
sb.append(tr.getID()+":"+tr.getTimeRecord()+"\n");
|
||||
}
|
||||
FileUtils.writetoFile(new String[]{sb.toString()}, sigIRC.BASEDIR+"records");
|
||||
}
|
||||
|
||||
public static int getRecord(int id) {
|
||||
for (TimeRecord tr : tmm.recordDatabase) {
|
||||
if (id==tr.getID()) {
|
||||
return tr.getTimeRecord();
|
||||
}
|
||||
}
|
||||
System.out.println("Warning! Time record for Monster ID "+id+" does not exist!");
|
||||
return ERROR_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to set the new record for this boss ID. If it doesn't exist, it creates a new record.
|
||||
* If the old record does not beat the currently stored record, it will not overwrite it.
|
||||
*/
|
||||
public static void setRecord(int id, int seconds) {
|
||||
for (TimeRecord tr : tmm.recordDatabase) {
|
||||
if (id==tr.getID()) {
|
||||
if (tr.getTimeRecord()>seconds) {
|
||||
tr.setTimeRecord(seconds);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
//If we got out here, we did not find one. So create a new record.
|
||||
tmm.recordDatabase.add(new TimeRecord(id,seconds));
|
||||
}
|
||||
|
||||
private void setTimeRecord(int seconds) {
|
||||
this.seconds = seconds;
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
return boss_id;
|
||||
}
|
||||
|
||||
public int getTimeRecord() {
|
||||
return seconds;
|
||||
}
|
||||
}
|
31
src/sig/modules/TouhouMother/TouhouMotherBossData.java
Normal file
31
src/sig/modules/TouhouMother/TouhouMotherBossData.java
Normal file
@ -0,0 +1,31 @@
|
||||
package sig.modules.TouhouMother;
|
||||
|
||||
public class TouhouMotherBossData {
|
||||
private String img;
|
||||
private String name;
|
||||
private int hp;
|
||||
private int id;
|
||||
|
||||
public TouhouMotherBossData(String name, int id, int hp, String img) {
|
||||
this.name=name;
|
||||
this.id=id;
|
||||
this.hp=hp;
|
||||
this.img=img;
|
||||
}
|
||||
|
||||
public String getImage() {
|
||||
return img;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getHP() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
return id;
|
||||
}
|
||||
}
|
135
src/sig/modules/TouhouMother/TouhouMotherCharacterData.java
Normal file
135
src/sig/modules/TouhouMother/TouhouMotherCharacterData.java
Normal file
@ -0,0 +1,135 @@
|
||||
package sig.modules.TouhouMother;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
public class TouhouMotherCharacterData {
|
||||
String name;
|
||||
int dmg_current;
|
||||
int dmg_total;
|
||||
int dmg_turns;
|
||||
int largest_hit;
|
||||
Color color;
|
||||
|
||||
public TouhouMotherCharacterData(String name, Color color) {
|
||||
this.name=name;
|
||||
this.dmg_current=0;
|
||||
this.dmg_total=0;
|
||||
this.dmg_turns=0;
|
||||
this.largest_hit=0;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public int getCurrentDamage() {
|
||||
return dmg_current;
|
||||
}
|
||||
|
||||
public void setCurrentDamage(int newdmg) {
|
||||
this.dmg_current = newdmg;
|
||||
}
|
||||
|
||||
public void addCurrentDamage(int dmg) {
|
||||
this.dmg_current += dmg;
|
||||
}
|
||||
|
||||
public int getTotalDamage() {
|
||||
return dmg_total;
|
||||
}
|
||||
|
||||
public void setTotalDamage(int newdmg) {
|
||||
this.dmg_total = newdmg;
|
||||
}
|
||||
|
||||
public void addTotalDamage(int dmg) {
|
||||
this.dmg_total += dmg;
|
||||
}
|
||||
|
||||
public int getDamageTurns() {
|
||||
return dmg_turns;
|
||||
}
|
||||
|
||||
public void setDamageTurns(int turns) {
|
||||
this.dmg_turns = turns;
|
||||
}
|
||||
|
||||
public void addDamageTurns(int turns) {
|
||||
this.dmg_turns += turns;
|
||||
}
|
||||
|
||||
public int getLargestHit() {
|
||||
return largest_hit;
|
||||
}
|
||||
|
||||
public void setLargestHit(int dmg) {
|
||||
setLargestHit(dmg,false);
|
||||
}
|
||||
|
||||
public void setLargestHit(int dmg, boolean force) {
|
||||
if (force || largest_hit<dmg) {
|
||||
largest_hit = dmg;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getDataProperty(DataProperty property) {
|
||||
switch (property) {
|
||||
case CURRENTDAMAGE:{
|
||||
return getCurrentDamage();
|
||||
}
|
||||
case TOTALDAMAGE:{
|
||||
return getTotalDamage();
|
||||
}
|
||||
case DAMAGETURNS:{
|
||||
return getDamageTurns();
|
||||
}
|
||||
case LARGESTHIT:{
|
||||
return getLargestHit();
|
||||
}
|
||||
default:{
|
||||
return getCurrentDamage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setDataProperty(DataProperty property, int val) {
|
||||
switch (property) {
|
||||
case CURRENTDAMAGE:{
|
||||
setCurrentDamage(val);
|
||||
}
|
||||
case TOTALDAMAGE:{
|
||||
setTotalDamage(val);
|
||||
}
|
||||
case DAMAGETURNS:{
|
||||
setDamageTurns(val);
|
||||
}
|
||||
case LARGESTHIT:{
|
||||
setLargestHit(val,true);
|
||||
}
|
||||
default:{
|
||||
setCurrentDamage(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void resetAllData() {
|
||||
setCurrentDamage(0);
|
||||
setTotalDamage(0);
|
||||
setDamageTurns(0);
|
||||
setLargestHit(0,true);
|
||||
}
|
||||
|
||||
public TouhouMotherCharacterData clone(){
|
||||
TouhouMotherCharacterData dataClone = new TouhouMotherCharacterData(name,color);
|
||||
dataClone.setCurrentDamage(getCurrentDamage());
|
||||
dataClone.setTotalDamage(getTotalDamage());
|
||||
dataClone.setDamageTurns(getDamageTurns());
|
||||
dataClone.setLargestHit(getLargestHit());
|
||||
return dataClone;
|
||||
}
|
||||
}
|
18
src/sig/modules/TouhouMother/TouhouPlayerCharacter.java
Normal file
18
src/sig/modules/TouhouMother/TouhouPlayerCharacter.java
Normal file
@ -0,0 +1,18 @@
|
||||
package sig.modules.TouhouMother;
|
||||
|
||||
public enum TouhouPlayerCharacter {
|
||||
REIMU(0),
|
||||
MARISA(1),
|
||||
YUUKA(2),
|
||||
MIMA(3);
|
||||
|
||||
private int id;
|
||||
|
||||
TouhouPlayerCharacter(int arrayID) {
|
||||
this.id=arrayID;
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
return id;
|
||||
}
|
||||
}
|
422
src/sig/modules/TouhouMotherModule.java
Normal file
422
src/sig/modules/TouhouMotherModule.java
Normal file
@ -0,0 +1,422 @@
|
||||
package sig.modules;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.Timer;
|
||||
|
||||
import sig.DrawUtils;
|
||||
import sig.FileUtils;
|
||||
import sig.Module;
|
||||
import sig.TextUtils;
|
||||
import sig.sigIRC;
|
||||
import sig.modules.TouhouMother.Button;
|
||||
import sig.modules.TouhouMother.DataProperty;
|
||||
import sig.modules.TouhouMother.IncreaseTouhouMotherClockCount;
|
||||
import sig.modules.TouhouMother.TimeRecord;
|
||||
import sig.modules.TouhouMother.TouhouMotherBossData;
|
||||
import sig.modules.TouhouMother.TouhouMotherCharacterData;
|
||||
import sig.modules.TouhouMother.TouhouPlayerCharacter;
|
||||
import sig.modules.utils.SemiValidInteger;
|
||||
import sig.modules.utils.SemiValidString;
|
||||
|
||||
public class TouhouMotherModule extends Module implements ActionListener{
|
||||
Timer filereadClock = new Timer(200,this);
|
||||
IncreaseTouhouMotherClockCount countev = new IncreaseTouhouMotherClockCount(this);
|
||||
Timer secondClock = new Timer(1000,countev);
|
||||
public int secondsCount = 0;
|
||||
String[] memory = new String[0];
|
||||
SemiValidInteger bossHP;
|
||||
SemiValidInteger bossID;
|
||||
SemiValidString gameData;
|
||||
int real_bossHP=SemiValidInteger.ERROR_VALUE;
|
||||
int real_bossID=SemiValidInteger.ERROR_VALUE;
|
||||
String real_gameData=SemiValidString.ERROR_VALUE;
|
||||
TouhouMotherBossData[] monsterDatabase = new TouhouMotherBossData[37];
|
||||
TouhouMotherCharacterData[] characterDatabase = new TouhouMotherCharacterData[4];
|
||||
|
||||
public List<TimeRecord> recordDatabase = new ArrayList<TimeRecord>();
|
||||
|
||||
int bossMaxHP=SemiValidInteger.ERROR_VALUE;
|
||||
TouhouMotherBossData currentBoss = null;
|
||||
BufferedImage bossImage = null;
|
||||
int lastCharacterAttacked=0;
|
||||
int lastBossHP=0;
|
||||
final int TIME_BETWEEN_DATA_DISPLAYS = 5 * 6;
|
||||
int data_display_toggle=0;
|
||||
int data_display_id=0;
|
||||
boolean hasDied=false;
|
||||
|
||||
Button updateButton;
|
||||
|
||||
public TouhouMotherModule(Rectangle2D bounds, String moduleName) {
|
||||
super(bounds, moduleName);
|
||||
PerformModuleInitialization();
|
||||
}
|
||||
|
||||
public TouhouMotherModule(Rectangle2D bounds, String moduleName, boolean enabled) {
|
||||
super(bounds, moduleName, enabled);
|
||||
PerformModuleInitialization();
|
||||
}
|
||||
|
||||
public void PerformModuleInitialization() {
|
||||
DefineMonsterDatabase();
|
||||
DefineCharacterDatabase();
|
||||
DisableTouhouMotherClockCount();
|
||||
PopulateRecordDatabase();
|
||||
DefineButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent ev) {
|
||||
memory = FileUtils.readFromFile(sigIRC.BASEDIR+"..\\memory");
|
||||
if (memory.length>=14) {
|
||||
ProcessMemoryData();
|
||||
ValidateAndControlMonsterData();
|
||||
}
|
||||
data_display_toggle++;
|
||||
if (data_display_toggle>TIME_BETWEEN_DATA_DISPLAYS) {
|
||||
data_display_id=(data_display_id+1)%DataProperty.values().length;
|
||||
data_display_toggle=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
EnableAndDisableTimer();
|
||||
}
|
||||
|
||||
public void draw(Graphics g) {
|
||||
if (enabled) {
|
||||
super.draw(g);
|
||||
if (currentBoss!=null) {
|
||||
DrawBossAndPlayerInfo(g);
|
||||
} else {
|
||||
DrawUtils.drawOutlineText(g, sigIRC.panel.programFont, (int)bounds.getX()+4, (int)bounds.getY()+4+16, 1, Color.BLACK, Color.WHITE,
|
||||
DataProperty.getDataPropertyBasedOnID(data_display_id).getDisplayName());
|
||||
DrawSortedHealthbarsBasedOnDataProperty(g, DataProperty.getDataPropertyBasedOnID(data_display_id), 0, -64);
|
||||
}
|
||||
updateButton.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawBossAndPlayerInfo(Graphics g) {
|
||||
g.drawImage(bossImage, (int)bounds.getX()+4, (int)bounds.getY()+4, sigIRC.panel);
|
||||
DrawUtils.drawOutlineText(g, sigIRC.panel.programFont, Math.min(bossImage.getWidth()+4,160)+(int)bounds.getX()+4, (int)bounds.getY()+4+16, 1, Color.BLACK, Color.WHITE,
|
||||
currentBoss.getName());
|
||||
DrawUtils.drawOutlineText(g, sigIRC.panel.userFont, Math.min(bossImage.getWidth()+4,160)+(int)bounds.getX()+4, (int)bounds.getY()+4+48, 1, Color.BLACK, Color.WHITE,
|
||||
real_bossHP+" / "+bossMaxHP +" ("+Math.round(((real_bossHP/(double)bossMaxHP)*100))+"%)");
|
||||
DrawUtils.drawHealthbar(g, new Rectangle(
|
||||
Math.min(bossImage.getWidth()+4,160)+(int)bounds.getX()+4,
|
||||
(int)bounds.getY()+4+20,
|
||||
(int)TextUtils.calculateStringBoundsFont(bossMaxHP+" / "+bossMaxHP +" ("+Math.round((1d*100))+"%", sigIRC.panel.userFont).getWidth(),
|
||||
8
|
||||
), real_bossHP/(double)bossMaxHP, ChooseHealthbarColor(real_bossHP/(double)bossMaxHP));
|
||||
DrawUtils.drawOutlineText(g, sigIRC.panel.userFont, Math.min(bossImage.getWidth()+4,160)+(int)bounds.getX()+16, (int)bounds.getY()+4+68, 1, Color.BLACK, Color.WHITE,
|
||||
TextUtils.convertSecondsToTimeFormat(secondsCount));
|
||||
int record = TimeRecord.getRecord(currentBoss.getID());
|
||||
if (record!=TimeRecord.ERROR_VALUE) {
|
||||
DrawUtils.drawOutlineText(g, sigIRC.panel.smallFont, Math.min(bossImage.getWidth()+4,160)+(int)bounds.getX()+
|
||||
TextUtils.calculateStringBoundsFont(TextUtils.convertSecondsToTimeFormat(secondsCount), sigIRC.panel.userFont).getWidth()+20,
|
||||
(int)bounds.getY()+4+72, 1, Color.BLACK, Color.WHITE,
|
||||
"RECORD "+TextUtils.convertSecondsToTimeFormat(record));
|
||||
}
|
||||
DrawSortedHealthbarsBasedOnDataProperty(g, DataProperty.CURRENTDAMAGE, 0, 0);
|
||||
}
|
||||
|
||||
public void DrawSortedHealthbarsBasedOnDataProperty(Graphics g, DataProperty property, int x, int y) {
|
||||
int pos = 0;
|
||||
int[] sorteddmg = new int[4];
|
||||
sorteddmg = SortByProperty(property);
|
||||
int totaldmg = calculateDataPropertyTotal(property);
|
||||
for (int i=0;i<sorteddmg.length;i++) {
|
||||
if (sorteddmg[i]!=-1 && characterDatabase[sorteddmg[i]].getDataProperty(property)>0) {
|
||||
DrawUtils.drawOutlineText(g, sigIRC.panel.userFont, Math.min(((bossImage!=null)?bossImage.getWidth():0)+4,160)+(int)bounds.getX()+4-Math.min(50, (bossImage!=null)?bossImage.getWidth():0)+x, (int)bounds.getY()+4+96+pos+y, 1, Color.BLACK, Color.WHITE,
|
||||
characterDatabase[sorteddmg[i]].getName());
|
||||
DrawUtils.drawHealthbar(g,
|
||||
new Rectangle(
|
||||
Math.min(((bossImage!=null)?bossImage.getWidth():0)+4,160)+(int)bounds.getX()+4+Math.max(0, 50-((bossImage!=null)?bossImage.getWidth():0))+x,
|
||||
(int)bounds.getY()+4+86+pos+y,
|
||||
96,
|
||||
10
|
||||
)
|
||||
, (double)characterDatabase[sorteddmg[i]].getDataProperty(property)/totaldmg, characterDatabase[sorteddmg[i]].getColor());
|
||||
DecimalFormat df = new DecimalFormat("0.0");
|
||||
DrawUtils.drawOutlineText(g, sigIRC.panel.smallFont, Math.min((bossImage!=null)?bossImage.getWidth():0+4,160)+(int)bounds.getX()+4+Math.max(0, 50-((bossImage!=null)?bossImage.getWidth():0))+108+x, (int)bounds.getY()+4+96+pos+y, 1, Color.BLACK, Color.WHITE,
|
||||
characterDatabase[sorteddmg[i]].getDataProperty(property)+" "+"("+df.format(((((double)characterDatabase[sorteddmg[i]].getDataProperty(property)/totaldmg))*100))+"%)");
|
||||
pos+=16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int[] SortByProperty(DataProperty property) {
|
||||
List<TouhouMotherCharacterData> needs_to_be_sorted = new ArrayList<TouhouMotherCharacterData>();
|
||||
for (int i=0;i<characterDatabase.length;i++) {
|
||||
needs_to_be_sorted.add(characterDatabase[i].clone());
|
||||
}
|
||||
int highest_val = Integer.MIN_VALUE;
|
||||
int arraypos = -1;
|
||||
int[] orderedslots = new int[4];
|
||||
int filledslots = 0;
|
||||
//System.out.println("Start of sorting algorithm:");
|
||||
while (filledslots<4) {
|
||||
for (int i=0;i<needs_to_be_sorted.size();i++) {
|
||||
if (needs_to_be_sorted.get(i).getDataProperty(property)>highest_val) {
|
||||
highest_val = needs_to_be_sorted.get(i).getDataProperty(property);
|
||||
//System.out.println("Set highest_val to "+highest_val);
|
||||
arraypos=i;
|
||||
}
|
||||
}
|
||||
orderedslots[filledslots++] = arraypos;
|
||||
if (arraypos!=-1) {
|
||||
needs_to_be_sorted.get(arraypos).setDataProperty(property, Integer.MIN_VALUE);
|
||||
}
|
||||
arraypos=-1;
|
||||
highest_val = Integer.MIN_VALUE;
|
||||
}
|
||||
//System.out.println("End result of orderedslots: "+Arrays.toString(orderedslots));
|
||||
return orderedslots;
|
||||
}
|
||||
private int calculateDataPropertyTotal(DataProperty property) {
|
||||
int total = 0;
|
||||
for (TouhouMotherCharacterData tmcd : characterDatabase) {
|
||||
total += tmcd.getDataProperty(property);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
private void PopulateRecordDatabase() {
|
||||
TimeRecord.tmm = this;
|
||||
TimeRecord.LoadRecordDatabase();
|
||||
}
|
||||
|
||||
private Color ChooseHealthbarColor(double pct) {
|
||||
if (pct>=0.66) {
|
||||
return new Color(64,168,64);
|
||||
} else
|
||||
if (pct>=0.33) {
|
||||
return new Color(240,220,0);
|
||||
} else
|
||||
return new Color(168,0,0);
|
||||
}
|
||||
private TouhouMotherBossData GetBossData(int bossID) {
|
||||
for (TouhouMotherBossData tmbd : monsterDatabase) {
|
||||
if (tmbd.getID()==bossID) {
|
||||
return tmbd;
|
||||
}
|
||||
}
|
||||
System.out.println("Invalid boss ID specified! Could not find boss with ID "+bossID+"!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ProcessMemoryData() {
|
||||
bossID = new SemiValidInteger(Arrays.copyOfRange(memory, 14, memory.length-1));
|
||||
if (GetBossData(bossID.getValidInteger())!=null) {
|
||||
bossHP = new SemiValidInteger(Arrays.copyOfRange(memory, 0, 8),GetBossData(bossID.getValidInteger()).getHP(),currentBoss!=null,(bossHP!=null)?bossHP.getTrustedSlot():-1);
|
||||
gameData = new SemiValidString(Arrays.copyOfRange(memory, 9, 13));
|
||||
System.out.println(bossHP.toString()+";"+bossID.toString()+";"+gameData.toString());
|
||||
real_bossHP = bossHP.getValidInteger();
|
||||
real_bossID = bossID.getValidInteger();
|
||||
real_gameData = gameData.getValidString();
|
||||
}
|
||||
System.out.print(real_gameData);
|
||||
if (real_gameData!=null && real_gameData.contains("sad thing that your adventures")) {
|
||||
hasDied=true;
|
||||
}
|
||||
}
|
||||
|
||||
private int GetLastAttacker(String data) {
|
||||
if (data.contains("Reimu")) {
|
||||
return TouhouPlayerCharacter.REIMU.getID();
|
||||
} else
|
||||
if (data.contains("Marisa")) {
|
||||
return TouhouPlayerCharacter.MARISA.getID();
|
||||
} else
|
||||
if (data.contains("Yuka")) {
|
||||
return TouhouPlayerCharacter.YUUKA.getID();
|
||||
} else
|
||||
if (data.contains("Mima")) {
|
||||
return TouhouPlayerCharacter.MIMA.getID();
|
||||
} else
|
||||
if (data.contains("Nitori") || data.contains("Sanae") ||
|
||||
data.contains("Patchouli") || data.contains("Iku")) {
|
||||
return -1;
|
||||
}
|
||||
return lastCharacterAttacked;
|
||||
}
|
||||
|
||||
public void ValidateAndControlMonsterData() {
|
||||
InitializeBossData();
|
||||
HandleBattleStats();
|
||||
}
|
||||
public void HandleBattleStats() {
|
||||
if (currentBoss!=null) {
|
||||
if (real_bossHP>bossMaxHP) {
|
||||
real_bossHP=bossMaxHP;
|
||||
}
|
||||
KillBossData();
|
||||
if (currentBoss!=null) {
|
||||
if (lastBossHP==0) {
|
||||
lastBossHP=real_bossHP;
|
||||
} else {
|
||||
if (lastBossHP>real_bossHP) {
|
||||
int diff = lastBossHP - real_bossHP;
|
||||
if (lastCharacterAttacked>=0) {
|
||||
characterDatabase[lastCharacterAttacked].addCurrentDamage(diff);
|
||||
characterDatabase[lastCharacterAttacked].addTotalDamage(diff);
|
||||
characterDatabase[lastCharacterAttacked].addDamageTurns(1);
|
||||
characterDatabase[lastCharacterAttacked].setLargestHit(diff);
|
||||
}
|
||||
lastBossHP=real_bossHP;
|
||||
}
|
||||
}
|
||||
lastCharacterAttacked = GetLastAttacker(real_gameData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializeBossData() {
|
||||
if (real_bossHP!=SemiValidInteger.ERROR_VALUE &&
|
||||
currentBoss==null) {
|
||||
currentBoss = GetBossData(real_bossID);
|
||||
if (currentBoss!=null) {
|
||||
bossMaxHP = currentBoss.getHP();
|
||||
secondsCount=0;
|
||||
secondClock.start();
|
||||
for (TouhouMotherCharacterData tmcd : characterDatabase) {
|
||||
tmcd.setCurrentDamage(0);
|
||||
}
|
||||
try {
|
||||
bossImage = ImageIO.read(new File(sigIRC.BASEDIR+"..\\Boss Sprites\\"+currentBoss.getImage()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void KillBossData() {
|
||||
if ((real_bossHP==SemiValidInteger.ERROR_VALUE &&
|
||||
currentBoss!=null) || hasDied) {
|
||||
if (bossImage!=null) {
|
||||
bossImage.flush();
|
||||
}
|
||||
int diff = lastBossHP;
|
||||
if (!hasDied) {
|
||||
if (lastCharacterAttacked>=0) {
|
||||
characterDatabase[lastCharacterAttacked].addCurrentDamage(diff);
|
||||
characterDatabase[lastCharacterAttacked].addTotalDamage(diff);
|
||||
characterDatabase[lastCharacterAttacked].addDamageTurns(1);
|
||||
characterDatabase[lastCharacterAttacked].setLargestHit(diff);
|
||||
}
|
||||
TimeRecord.setRecord(currentBoss.getID(), secondsCount);
|
||||
TimeRecord.SaveRecordDatabase();
|
||||
} else {
|
||||
for (TouhouMotherCharacterData tmcd : characterDatabase) {
|
||||
tmcd.resetAllData();
|
||||
}
|
||||
hasDied=false;
|
||||
}
|
||||
bossMaxHP=SemiValidInteger.ERROR_VALUE;
|
||||
currentBoss=null;
|
||||
lastBossHP=0;
|
||||
}
|
||||
}
|
||||
|
||||
private void DefineCharacterDatabase() {
|
||||
characterDatabase[TouhouPlayerCharacter.REIMU.getID()] = new TouhouMotherCharacterData("Reimu",new Color(255,70,70));
|
||||
characterDatabase[TouhouPlayerCharacter.MARISA.getID()] = new TouhouMotherCharacterData("Marisa",new Color(255,200,70));
|
||||
characterDatabase[TouhouPlayerCharacter.YUUKA.getID()] = new TouhouMotherCharacterData("Yuuka",new Color(35,140,35));
|
||||
characterDatabase[TouhouPlayerCharacter.MIMA.getID()] = new TouhouMotherCharacterData("Mima",new Color(55,100,200));
|
||||
}
|
||||
|
||||
private void DefineMonsterDatabase() {
|
||||
int i=0;
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Cirno", 1, 500, "Cirno.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Starman Jr", 3, 888, "Starman_Junior.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Masked Maid Girl", 4, 1000, "Masked_Maid_Girl.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Youmu Shall Not Lose", 11, 2111, "Youmu_Never_Loses.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Alice (Sick)", 15, 3500, "TME_15.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Galbangor", 23, 4000, "TME_23.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Miss Iku", 24, 3000, "TME_24.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Starman EX", 33, 5558, "TME_33.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("V-1969", 38, 8000, "TME_38.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Severed Head", 44, 7209, "TME_44.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Lady Shinki", 53, 10000, "TME_53.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Cirno", 63, 8888, "TME_63.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Strange Patchouli", 68, 10000, "TME_68.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("DEATH", 73, 10000, "TME_73.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Count Remilia", 55, 16000, "TME_55.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Miss Sanae", 74, 6000, "TME_74.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Pitch Black Rumia", 75, 8888, "TME_75.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Rinbokusan", 83, 10000, "TME_83.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("New Udonge", -101, 8888, "TME_-101.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Roboster", -84, 9999, "TME_-84.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Ancestral Starman", 103, 9999, "TME_103.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Miss Yuugi", 104, 12345, "TME_104.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Sparky", 105, 8000, "TME_105.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Keine", 136, 10000, "TME_136.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Miracle Udon", 137, 6000, "TME_137.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("a", -99, 26000, "TME_-99.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Mima", -10000, 41, "TME_-10000.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Ness", 900000, 1500, "TME_900000.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("General Pigmask", 202, 15000, "TME_202.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Proto-NKC", 204, 30000, "TME_204.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Tenshi", 999997, 30000, "TME_999997.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("The Devil's Machine", 999998, 14000, "DevilMachine.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("R-IN", 122, 999999, "TME_122.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("S-IN", 138, 999999, "TME_138.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Heavy Kisume", 200, 999999, "TME_200.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("KA-75", 203, 999999, "TME_203.png");
|
||||
monsterDatabase[i++] = new TouhouMotherBossData("Gensokyo", 999999, 900000, "TME_999999.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the timer, by enabling or disabling it based on enabled state.
|
||||
*/
|
||||
public void EnableAndDisableTimer() {
|
||||
if (enabled) {
|
||||
if (!filereadClock.isRunning()) {
|
||||
filereadClock.start();
|
||||
}
|
||||
} else {
|
||||
if (filereadClock.isRunning()) {
|
||||
filereadClock.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisableTouhouMotherClockCount() {
|
||||
secondClock.setInitialDelay(1000);
|
||||
secondClock.stop();
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent ev) {
|
||||
updateButton.onClickEvent(ev);
|
||||
}
|
||||
public void mouseWheel(MouseWheelEvent ev) {
|
||||
updateButton.onMouseWheelEvent(ev);
|
||||
}
|
||||
|
||||
private void DefineButton() {
|
||||
updateButton = new Button(this, //56x20 pixels
|
||||
new File(sigIRC.BASEDIR+"..\\update.png"),
|
||||
(int)bounds.getX()+320-56,(int)bounds.getY()+sigIRC.panel.getHeight()/2-20);
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds() {
|
||||
return bounds;
|
||||
}
|
||||
}
|
65
src/sig/modules/utils/SemiValidInteger.java
Normal file
65
src/sig/modules/utils/SemiValidInteger.java
Normal file
@ -0,0 +1,65 @@
|
||||
package sig.modules.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import sig.TextUtils;
|
||||
|
||||
public class SemiValidInteger {
|
||||
final public static int ERROR_VALUE = Integer.MIN_VALUE;
|
||||
String[] values;
|
||||
int bossHP=Integer.MAX_VALUE;
|
||||
boolean initialized=true;
|
||||
int trustedslot = -1;
|
||||
|
||||
public SemiValidInteger(String[] vals) {
|
||||
this.values = vals;
|
||||
}
|
||||
|
||||
public SemiValidInteger(String[] vals, Integer bossHP, boolean initialized) {
|
||||
this.bossHP=bossHP;
|
||||
this.values=vals;
|
||||
this.initialized=initialized;
|
||||
}
|
||||
|
||||
public SemiValidInteger(String[] vals, Integer bossHP, boolean initialized, int trustedslot) {
|
||||
this.bossHP=bossHP;
|
||||
this.values=vals;
|
||||
this.initialized=initialized;
|
||||
this.trustedslot=trustedslot;
|
||||
}
|
||||
|
||||
public int getValidInteger() {
|
||||
if (initialized && trustedslot!=-1) {
|
||||
if (TextUtils.isNumeric(values[trustedslot]) && TextUtils.isInteger(values[trustedslot], 10) && values[trustedslot].length()<Integer.toString(Integer.MAX_VALUE).length()) {
|
||||
int testnumb = Integer.parseInt(values[trustedslot]);
|
||||
if (passesTestConditions(testnumb)) {
|
||||
return testnumb;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i=0;i<values.length;i++) {
|
||||
if (TextUtils.isNumeric(values[i]) && TextUtils.isInteger(values[i], 10) && values[i].length()<Integer.toString(Integer.MAX_VALUE).length()) {
|
||||
int testnumb = Integer.parseInt(values[i]);
|
||||
if (passesTestConditions(testnumb)) {
|
||||
trustedslot = i;
|
||||
return testnumb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("WARNING! Could not find valid value for SemiValidInteger["+values.length+"]!");
|
||||
return ERROR_VALUE;
|
||||
}
|
||||
|
||||
public int getTrustedSlot() {
|
||||
return trustedslot;
|
||||
}
|
||||
|
||||
public boolean passesTestConditions(int testnumb) {
|
||||
return testnumb!=0 && testnumb<1000000 && (((!initialized && testnumb==bossHP) || (initialized && testnumb<=bossHP)) || bossHP==Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "SemiValidInteger "+Arrays.toString(values);
|
||||
}
|
||||
}
|
32
src/sig/modules/utils/SemiValidString.java
Normal file
32
src/sig/modules/utils/SemiValidString.java
Normal file
@ -0,0 +1,32 @@
|
||||
package sig.modules.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import sig.TextUtils;
|
||||
|
||||
public class SemiValidString {
|
||||
final public static String ERROR_VALUE = "nil";
|
||||
String[] values;
|
||||
|
||||
public SemiValidString(String[] vals) {
|
||||
this.values = vals;
|
||||
}
|
||||
|
||||
public String getValidString() {
|
||||
for (String val : values) {
|
||||
if (passesTestConditions(val)) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
System.out.println("WARNING! Could not find valid value for SemiValidString["+values.length+"]!");
|
||||
return ERROR_VALUE;
|
||||
}
|
||||
|
||||
public boolean passesTestConditions(String testval) {
|
||||
return !(testval.equalsIgnoreCase("nil") || TextUtils.isNumeric(testval));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "SemiValidString "+Arrays.toString(values);
|
||||
}
|
||||
}
|
237
src/sig/sigIRC.java
Normal file
237
src/sig/sigIRC.java
Normal file
@ -0,0 +1,237 @@
|
||||
package sig;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.Timer;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import sig.modules.TouhouMotherModule;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class sigIRC{
|
||||
public static MyPanel panel = null;
|
||||
public static List<ScrollingText> textobj = new ArrayList<ScrollingText>();
|
||||
public static List<TextRow> rowobj = new ArrayList<TextRow>();
|
||||
public static List<Emoticon> emoticons = new ArrayList<Emoticon>();
|
||||
public static List<TwitchEmote> twitchemoticons = new ArrayList<TwitchEmote>();
|
||||
public static List<CustomSound> customsounds = new ArrayList<CustomSound>();
|
||||
public static List<Module> modules = new ArrayList<Module>();
|
||||
static UpdateEvent updater = new UpdateEvent();
|
||||
static Timer programClock = new Timer(32,updater);
|
||||
final public static int TEXTSCROLLSPD = 4;
|
||||
final public static int ROWSEPARATION = 64;
|
||||
final public static String BASEDIR = "D:\\Documents\\Touhou Mother Speedrun\\sigIRC\\";
|
||||
final public static String WINDOWTITLE = "sigIRCv2";
|
||||
|
||||
public static void main(String[] args) {
|
||||
String server = "irc.chat.twitch.tv";
|
||||
String nickname = "SigoNitori";
|
||||
String channel = "#sigonitori";
|
||||
|
||||
String[] filedata = FileUtils.readFromFile(BASEDIR+"oauthToken.txt");
|
||||
|
||||
String oauth = filedata[0];
|
||||
|
||||
WriteBreakToLogFile();
|
||||
|
||||
programClock.start();
|
||||
|
||||
InitializeRows(3);
|
||||
InitializeCustomSounds();
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
createAndShowGUI();
|
||||
|
||||
InitializeModules();
|
||||
performTwitchEmoteUpdate();
|
||||
}
|
||||
});
|
||||
InitializeIRCConnection(server, nickname, channel, oauth);
|
||||
}
|
||||
|
||||
private static void InitializeModules() {
|
||||
modules.add(new TouhouMotherModule(
|
||||
new Rectangle(0,panel.getHeight()/2,320,panel.getHeight()/2),
|
||||
"Touhou Mother"
|
||||
));
|
||||
}
|
||||
|
||||
private static void InitializeCustomSounds() {
|
||||
customsounds.add(new CustomSound("monkeyman5876", "Howler Monkeys Howling (Very Funny)-Pia8ku7jUNg.wav"));
|
||||
customsounds.add(new CustomSound("kuroplz", "Kuroyukihime Burst Link !-tv6wMw7KU9o.wav"));
|
||||
customsounds.add(new CustomSound("samusaran458", "Samus Appears - Metroid Prime [OST]-G8frLXCHtqM.wav"));
|
||||
}
|
||||
|
||||
public static void InitializeIRCConnection(String server, String nickname, String channel, String oauth) {
|
||||
Socket socket;
|
||||
try {
|
||||
socket = new Socket(server, 6667);
|
||||
BufferedWriter writer = new BufferedWriter(
|
||||
new OutputStreamWriter(socket.getOutputStream( )));
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(socket.getInputStream( )));
|
||||
|
||||
// Log on to the server.
|
||||
writer.write("PASS " + oauth + "\r\n");
|
||||
writer.write("NICK " + nickname + "\r\n");
|
||||
writer.flush( );
|
||||
if (VerifyLogin(reader)) {
|
||||
//panel.addMessage("We are now logged in.");
|
||||
writer.write("JOIN " + channel + "\r\n");
|
||||
writer.flush();
|
||||
runIRCLoop(channel, writer, reader);
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
InitializeIRCConnection(server,nickname,channel,oauth);
|
||||
}
|
||||
|
||||
public static void WriteBreakToLogFile() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
File file = new File(BASEDIR+"logs\\log_"+(cal.get(Calendar.MONTH)+1)+"_"+cal.get(Calendar.DAY_OF_MONTH)+"_"+cal.get(Calendar.YEAR)+".txt");
|
||||
if (file.exists()) {
|
||||
FileUtils.logToFile("\n---------------------------\n", BASEDIR+"logs\\log_"+(cal.get(Calendar.MONTH)+1)+"_"+cal.get(Calendar.DAY_OF_MONTH)+"_"+cal.get(Calendar.YEAR)+".txt");
|
||||
}
|
||||
}
|
||||
|
||||
private static void performTwitchEmoteUpdate() {
|
||||
try {
|
||||
JSONObject twitchemotes = FileUtils.readJsonFromUrl("https://twitchemotes.com/api_cache/v2/global.json");
|
||||
JSONObject emotelist = twitchemotes.getJSONObject("emotes");
|
||||
JSONObject templatelist = twitchemotes.getJSONObject("template");
|
||||
String templateurl = templatelist.getString("small");
|
||||
for (String emotes : emotelist.keySet()) {
|
||||
JSONObject emote = emotelist.getJSONObject(emotes);
|
||||
int id = emote.getInt("image_id");
|
||||
String emoteurl = templateurl.replace("{image_id}", ""+id);
|
||||
emoticons.add(new Emoticon(emotes, new URL(emoteurl)));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
emoticons.add(new Emoticon(":)","1"));
|
||||
emoticons.add(new Emoticon(":(","2"));
|
||||
emoticons.add(new Emoticon(":o","3"));
|
||||
emoticons.add(new Emoticon(":O","3"));
|
||||
emoticons.add(new Emoticon(":z","4"));
|
||||
emoticons.add(new Emoticon(":Z","4"));
|
||||
emoticons.add(new Emoticon("B)","5"));
|
||||
emoticons.add(new Emoticon(":\\","6"));
|
||||
emoticons.add(new Emoticon(":/","6"));
|
||||
emoticons.add(new Emoticon(";)","7"));
|
||||
emoticons.add(new Emoticon(";p","8"));
|
||||
emoticons.add(new Emoticon(";P","8"));
|
||||
emoticons.add(new Emoticon(":p","9"));
|
||||
emoticons.add(new Emoticon(":P","9"));
|
||||
emoticons.add(new Emoticon("R)","10"));
|
||||
emoticons.add(new Emoticon("o_O","20"));
|
||||
emoticons.add(new Emoticon("O_o","20"));
|
||||
emoticons.add(new Emoticon(":D","11"));
|
||||
emoticons.add(new Emoticon(">(","12"));
|
||||
emoticons.add(new Emoticon("<3","13"));
|
||||
}
|
||||
|
||||
/*private static void DefineEmoticons() {
|
||||
//emoticons.add(new Emoticon(sigIRC.BASEDIR+"Emotes\\;).png"));
|
||||
File folder = new File(sigIRC.BASEDIR+"Emotes\\");
|
||||
for (File f : folder.listFiles()) {
|
||||
emoticons.add(new Emoticon(f.getAbsolutePath()));
|
||||
}
|
||||
}*/
|
||||
|
||||
private static void InitializeRows(int rowcount) {
|
||||
for (int i=0;i<rowcount;i++) {
|
||||
rowobj.add(new TextRow(32+ROWSEPARATION*i));
|
||||
}
|
||||
}
|
||||
|
||||
public static void runIRCLoop(String channel, BufferedWriter writer, BufferedReader reader) throws IOException {
|
||||
String line;
|
||||
while ((line = reader.readLine( )) != null) {
|
||||
if (line.toLowerCase( ).startsWith("PING ")) {
|
||||
// We must respond to PINGs to avoid being disconnected.
|
||||
writer.write("PONG " + line.substring(5) + "\r\n");
|
||||
writer.write("PRIVMSG " + channel + " :I got pinged!\r\n");
|
||||
writer.flush( );
|
||||
}
|
||||
else {
|
||||
// Print the raw line received by the bot.
|
||||
if (MessageIsAllowed(line)) {
|
||||
String filteredMessage = FilterMessage(line);
|
||||
panel.addMessage(filteredMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String FilterMessage(String line) {
|
||||
System.out.println("Original Message: "+line);
|
||||
String username = line.substring(1, line.indexOf("!"));
|
||||
String cutstring = "#sigonitori :";
|
||||
String message = line.substring(line.indexOf(cutstring)+cutstring.length(), line.length());
|
||||
return username+": "+ message;
|
||||
}
|
||||
|
||||
private static boolean MessageIsAllowed(String line) {
|
||||
if (line.contains("PRIVMSG")) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void createAndShowGUI() {
|
||||
JFrame f = new JFrame("sigIRCv2");
|
||||
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
sigIRC.panel = new MyPanel();
|
||||
sigIRC.panel.setBackground(Color.CYAN);
|
||||
f.add(sigIRC.panel);
|
||||
f.pack();
|
||||
f.setVisible(true);
|
||||
}
|
||||
|
||||
public static boolean VerifyLogin(BufferedReader reader) throws IOException {
|
||||
String line = null;
|
||||
while ((line = reader.readLine( )) != null) {
|
||||
if (line.indexOf("004") >= 0) {
|
||||
return true;
|
||||
}
|
||||
else if (line.indexOf("433") >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void createEmoticon(Emoticon emote, ScrollingText textref, int x, int y) {
|
||||
twitchemoticons.add(new TwitchEmote(emote,textref,x,y));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user