commit
c07375c979
@ -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> |
@ -0,0 +1 @@ |
|||||||
|
/bin/ |
@ -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> |
@ -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 |
@ -0,0 +1 @@ |
|||||||
|
sigonitori: This will go in the log 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(); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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 + "]"; |
||||||
|
} |
||||||
|
} |
@ -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)); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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 + ">"; |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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) { |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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(":")); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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++; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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…
Reference in new issue