Config en .json terminée + advancedstatus refait.

This commit is contained in:
M4TH1EU 2019-07-20 21:57:52 +02:00
parent f0a0e539a3
commit bdad98669b
27 changed files with 2539 additions and 2620 deletions

View File

@ -40,6 +40,7 @@ SOFTWARE.
* A comma delimited list can be converted into a JSONArray of JSONObjects. * 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 * The names for the elements in the JSONObjects can be taken from the names
* in the first row. * in the first row.
*
* @author JSON.org * @author JSON.org
* @version 2016-05-01 * @version 2016-05-01
*/ */
@ -48,6 +49,7 @@ public class CDL {
/** /**
* Get the next value. The value can be wrapped in quotes. The value can * Get the next value. The value can be wrapped in quotes. The value can
* be empty. * be empty.
*
* @param x A JSONTokener of the source text. * @param x A JSONTokener of the source text.
* @return The value string, or null if empty. * @return The value string, or null if empty.
* @throws JSONException if the quoted string is badly formed. * @throws JSONException if the quoted string is badly formed.
@ -60,49 +62,50 @@ public class CDL {
c = x.next(); c = x.next();
} while (c == ' ' || c == '\t'); } while (c == ' ' || c == '\t');
switch (c) { switch (c) {
case 0: case 0:
return null; return null;
case '"': case '"':
case '\'': case '\'':
q = c; q = c;
sb = new StringBuffer(); sb = new StringBuffer();
for (;;) { for (; ; ) {
c = x.next(); c = x.next();
if (c == q) { if (c == q) {
//Handle escaped double-quote //Handle escaped double-quote
char nextC = x.next(); char nextC = x.next();
if(nextC != '\"') { if (nextC != '\"') {
// if our quote was the end of the file, don't step // if our quote was the end of the file, don't step
if(nextC > 0) { if (nextC > 0) {
x.back(); x.back();
}
break;
} }
break;
} }
if (c == 0 || c == '\n' || c == '\r') {
throw x.syntaxError("Missing close quote '" + q + "'.");
}
sb.append(c);
} }
if (c == 0 || c == '\n' || c == '\r') { return sb.toString();
throw x.syntaxError("Missing close quote '" + q + "'."); case ',':
} x.back();
sb.append(c); return "";
} default:
return sb.toString(); x.back();
case ',': return x.nextTo(',');
x.back();
return "";
default:
x.back();
return x.nextTo(',');
} }
} }
/** /**
* Produce a JSONArray of strings from a row of comma delimited values. * Produce a JSONArray of strings from a row of comma delimited values.
*
* @param x A JSONTokener of the source text. * @param x A JSONTokener of the source text.
* @return A JSONArray of strings. * @return A JSONArray of strings.
* @throws JSONException * @throws JSONException
*/ */
public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
JSONArray ja = new JSONArray(); JSONArray ja = new JSONArray();
for (;;) { for (; ; ) {
String value = getValue(x); String value = getValue(x);
char c = x.next(); char c = x.next();
if (value == null || if (value == null ||
@ -110,7 +113,7 @@ public class CDL {
return null; return null;
} }
ja.put(value); ja.put(value);
for (;;) { for (; ; ) {
if (c == ',') { if (c == ',') {
break; break;
} }
@ -119,7 +122,7 @@ public class CDL {
return ja; return ja;
} }
throw x.syntaxError("Bad character '" + c + "' (" + throw x.syntaxError("Bad character '" + c + "' (" +
(int)c + ")."); (int) c + ").");
} }
c = x.next(); c = x.next();
} }
@ -129,23 +132,25 @@ public class CDL {
/** /**
* Produce a JSONObject from a row of comma delimited text, using a * Produce a JSONObject from a row of comma delimited text, using a
* parallel JSONArray of strings to provides the names of the elements. * parallel JSONArray of strings to provides the names of the elements.
*
* @param names A JSONArray of names. This is commonly obtained from the * @param names A JSONArray of names. This is commonly obtained from the
* first row of a comma delimited text file using the rowToJSONArray * first row of a comma delimited text file using the rowToJSONArray
* method. * method.
* @param x A JSONTokener of the source text. * @param x A JSONTokener of the source text.
* @return A JSONObject combining the names and values. * @return A JSONObject combining the names and values.
* @throws JSONException * @throws JSONException
*/ */
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
throws JSONException { throws JSONException {
JSONArray ja = rowToJSONArray(x); JSONArray ja = rowToJSONArray(x);
return ja != null ? ja.toJSONObject(names) : null; return ja != null ? ja.toJSONObject(names) : null;
} }
/** /**
* Produce a comma delimited text row from a JSONArray. Values containing * Produce a comma delimited text row from a JSONArray. Values containing
* the comma character will be quoted. Troublesome characters may be * the comma character will be quoted. Troublesome characters may be
* removed. * removed.
*
* @param ja A JSONArray of strings. * @param ja A JSONArray of strings.
* @return A string ending in NEWLINE. * @return A string ending in NEWLINE.
*/ */
@ -182,6 +187,7 @@ public class CDL {
/** /**
* Produce a JSONArray of JSONObjects from a comma delimited text string, * Produce a JSONArray of JSONObjects from a comma delimited text string,
* using the first row as a source of names. * using the first row as a source of names.
*
* @param string The comma delimited text. * @param string The comma delimited text.
* @return A JSONArray of JSONObjects. * @return A JSONArray of JSONObjects.
* @throws JSONException * @throws JSONException
@ -193,6 +199,7 @@ public class CDL {
/** /**
* Produce a JSONArray of JSONObjects from a comma delimited text string, * Produce a JSONArray of JSONObjects from a comma delimited text string,
* using the first row as a source of names. * using the first row as a source of names.
*
* @param x The JSONTokener containing the comma delimited text. * @param x The JSONTokener containing the comma delimited text.
* @return A JSONArray of JSONObjects. * @return A JSONArray of JSONObjects.
* @throws JSONException * @throws JSONException
@ -204,7 +211,8 @@ public class CDL {
/** /**
* Produce a JSONArray of JSONObjects from a comma delimited text string * Produce a JSONArray of JSONObjects from a comma delimited text string
* using a supplied JSONArray as the source of element names. * using a supplied JSONArray as the source of element names.
* @param names A JSONArray of strings. *
* @param names A JSONArray of strings.
* @param string The comma delimited text. * @param string The comma delimited text.
* @return A JSONArray of JSONObjects. * @return A JSONArray of JSONObjects.
* @throws JSONException * @throws JSONException
@ -217,8 +225,9 @@ public class CDL {
/** /**
* Produce a JSONArray of JSONObjects from a comma delimited text string * Produce a JSONArray of JSONObjects from a comma delimited text string
* using a supplied JSONArray as the source of element names. * using a supplied JSONArray as the source of element names.
*
* @param names A JSONArray of strings. * @param names A JSONArray of strings.
* @param x A JSONTokener of the source text. * @param x A JSONTokener of the source text.
* @return A JSONArray of JSONObjects. * @return A JSONArray of JSONObjects.
* @throws JSONException * @throws JSONException
*/ */
@ -228,7 +237,7 @@ public class CDL {
return null; return null;
} }
JSONArray ja = new JSONArray(); JSONArray ja = new JSONArray();
for (;;) { for (; ; ) {
JSONObject jo = rowToJSONObject(names, x); JSONObject jo = rowToJSONObject(names, x);
if (jo == null) { if (jo == null) {
break; break;
@ -246,6 +255,7 @@ public class CDL {
* Produce a comma delimited text from a JSONArray of JSONObjects. The * Produce a comma delimited text from a JSONArray of JSONObjects. The
* first row will be a list of names obtained by inspecting the first * first row will be a list of names obtained by inspecting the first
* JSONObject. * JSONObject.
*
* @param ja A JSONArray of JSONObjects. * @param ja A JSONArray of JSONObjects.
* @return A comma delimited text. * @return A comma delimited text.
* @throws JSONException * @throws JSONException
@ -265,8 +275,9 @@ public class CDL {
* Produce a comma delimited text from a JSONArray of JSONObjects using * 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 * a provided list of names. The list of names is not included in the
* output. * output.
*
* @param names A JSONArray of strings. * @param names A JSONArray of strings.
* @param ja A JSONArray of JSONObjects. * @param ja A JSONArray of JSONObjects.
* @return A comma delimited text. * @return A comma delimited text.
* @throws JSONException * @throws JSONException
*/ */

View File

@ -27,6 +27,7 @@ SOFTWARE.
/** /**
* Convert a web browser cookie specification to a JSONObject and back. * Convert a web browser cookie specification to a JSONObject and back.
* JSON and Cookies are both notations for name/value pairs. * JSON and Cookies are both notations for name/value pairs.
*
* @author JSON.org * @author JSON.org
* @version 2015-12-09 * @version 2015-12-09
*/ */
@ -41,20 +42,21 @@ public class Cookie {
* only a convention, not a standard. Often, cookies are expected to have * only a convention, not a standard. Often, cookies are expected to have
* encoded values. We encode '=' and ';' because we must. We encode '%' and * encoded values. We encode '=' and ';' because we must. We encode '%' and
* '+' because they are meta characters in URL encoding. * '+' because they are meta characters in URL encoding.
*
* @param string The source string. * @param string The source string.
* @return The escaped result. * @return The escaped result.
*/ */
public static String escape(String string) { public static String escape(String string) {
char c; char c;
String s = string.trim(); String s = string.trim();
int length = s.length(); int length = s.length();
StringBuilder sb = new StringBuilder(length); StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i += 1) { for (int i = 0; i < length; i += 1) {
c = s.charAt(i); c = s.charAt(i);
if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') {
sb.append('%'); sb.append('%');
sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16)); sb.append(Character.forDigit((char) ((c >>> 4) & 0x0f), 16));
sb.append(Character.forDigit((char)(c & 0x0f), 16)); sb.append(Character.forDigit((char) (c & 0x0f), 16));
} else { } else {
sb.append(c); sb.append(c);
} }
@ -73,15 +75,16 @@ public class Cookie {
* stored under the key "value". This method does not do checking or * stored under the key "value". This method does not do checking or
* validation of the parameters. It only converts the cookie string into * validation of the parameters. It only converts the cookie string into
* a JSONObject. * a JSONObject.
*
* @param string The cookie specification string. * @param string The cookie specification string.
* @return A JSONObject containing "name", "value", and possibly other * @return A JSONObject containing "name", "value", and possibly other
* members. * members.
* @throws JSONException * @throws JSONException
*/ */
public static JSONObject toJSONObject(String string) throws JSONException { public static JSONObject toJSONObject(String string) throws JSONException {
String name; String name;
JSONObject jo = new JSONObject(); JSONObject jo = new JSONObject();
Object value; Object value;
JSONTokener x = new JSONTokener(string); JSONTokener x = new JSONTokener(string);
jo.put("name", x.nextTo('=')); jo.put("name", x.nextTo('='));
x.next('='); x.next('=');
@ -111,6 +114,7 @@ public class Cookie {
* If the JSONObject contains "expires", "domain", "path", or "secure" * If the JSONObject contains "expires", "domain", "path", or "secure"
* members, they will be appended to the cookie specification string. * members, they will be appended to the cookie specification string.
* All other members are ignored. * All other members are ignored.
*
* @param jo A JSONObject * @param jo A JSONObject
* @return A cookie specification string * @return A cookie specification string
* @throws JSONException * @throws JSONException
@ -142,9 +146,10 @@ public class Cookie {
/** /**
* Convert <code>%</code><i>hh</i> sequences to single characters, and * Convert <code>%</code><i>hh</i> sequences to single characters, and
* convert plus to space. * convert plus to space.
*
* @param string A string that may contain * @param string A string that may contain
* <code>+</code>&nbsp;<small>(plus)</small> and * <code>+</code>&nbsp;<small>(plus)</small> and
* <code>%</code><i>hh</i> sequences. * <code>%</code><i>hh</i> sequences.
* @return The unescaped string. * @return The unescaped string.
*/ */
public static String unescape(String string) { public static String unescape(String string) {
@ -158,7 +163,7 @@ public class Cookie {
int d = JSONTokener.dehexchar(string.charAt(i + 1)); int d = JSONTokener.dehexchar(string.charAt(i + 1));
int e = JSONTokener.dehexchar(string.charAt(i + 2)); int e = JSONTokener.dehexchar(string.charAt(i + 2));
if (d >= 0 && e >= 0) { if (d >= 0 && e >= 0) {
c = (char)(d * 16 + e); c = (char) (d * 16 + e);
i += 2; i += 2;
} }
} }

View File

@ -26,6 +26,7 @@ SOFTWARE.
/** /**
* Convert a web browser cookie list string to a JSONObject and back. * Convert a web browser cookie list string to a JSONObject and back.
*
* @author JSON.org * @author JSON.org
* @version 2015-12-09 * @version 2015-12-09
*/ */
@ -36,11 +37,12 @@ public class CookieList {
* of name/value pairs. The names are separated from the values by '='. * of name/value pairs. The names are separated from the values by '='.
* The pairs are separated by ';'. The names and the values * The pairs are separated by ';'. The names and the values
* will be unescaped, possibly converting '+' and '%' sequences. * will be unescaped, possibly converting '+' and '%' sequences.
* * <p>
* To add a cookie to a cookie list, * To add a cookie to a cookie list,
* cookielistJSONObject.put(cookieJSONObject.getString("name"), * cookielistJSONObject.put(cookieJSONObject.getString("name"),
* cookieJSONObject.getString("value")); * cookieJSONObject.getString("value"));
* @param string A cookie list string *
* @param string A cookie list string
* @return A JSONObject * @return A JSONObject
* @throws JSONException * @throws JSONException
*/ */
@ -61,12 +63,13 @@ public class CookieList {
* of name/value pairs. The names are separated from the values by '='. * of name/value pairs. The names are separated from the values by '='.
* The pairs are separated by ';'. The characters '%', '+', '=', and ';' * The pairs are separated by ';'. The characters '%', '+', '=', and ';'
* in the names and values are replaced by "%hh". * in the names and values are replaced by "%hh".
*
* @param jo A JSONObject * @param jo A JSONObject
* @return A cookie list string * @return A cookie list string
* @throws JSONException * @throws JSONException
*/ */
public static String toString(JSONObject jo) throws JSONException { public static String toString(JSONObject jo) throws JSONException {
boolean b = false; boolean b = false;
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
// Don't use the new entrySet API to maintain Android support // Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) { for (final String key : jo.keySet()) {

View File

@ -28,12 +28,15 @@ import java.util.Locale;
/** /**
* Convert an HTTP header to a JSONObject and back. * Convert an HTTP header to a JSONObject and back.
*
* @author JSON.org * @author JSON.org
* @version 2015-12-09 * @version 2015-12-09
*/ */
public class HTTP { public class HTTP {
/** Carriage return/line feed. */ /**
* Carriage return/line feed.
*/
public static final String CRLF = "\r\n"; public static final String CRLF = "\r\n";
/** /**
@ -63,15 +66,16 @@ public class HTTP {
* ...}</pre> * ...}</pre>
* It does no further checking or conversion. It does not parse dates. * It does no further checking or conversion. It does not parse dates.
* It does not do '%' transforms on URLs. * It does not do '%' transforms on URLs.
*
* @param string An HTTP header string. * @param string An HTTP header string.
* @return A JSONObject containing the elements and attributes * @return A JSONObject containing the elements and attributes
* of the XML string. * of the XML string.
* @throws JSONException * @throws JSONException
*/ */
public static JSONObject toJSONObject(String string) throws JSONException { public static JSONObject toJSONObject(String string) throws JSONException {
JSONObject jo = new JSONObject(); JSONObject jo = new JSONObject();
HTTPTokener x = new HTTPTokener(string); HTTPTokener x = new HTTPTokener(string);
String token; String token;
token = x.nextToken(); token = x.nextToken();
if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) {
@ -119,13 +123,14 @@ public class HTTP {
* }</pre> * }</pre>
* Any other members of the JSONObject will be output as HTTP fields. * Any other members of the JSONObject will be output as HTTP fields.
* The result will end with two CRLF pairs. * The result will end with two CRLF pairs.
*
* @param jo A JSONObject * @param jo A JSONObject
* @return An HTTP header string. * @return An HTTP header string.
* @throws JSONException if the object does not contain enough * @throws JSONException if the object does not contain enough
* information. * information.
*/ */
public static String toString(JSONObject jo) throws JSONException { public static String toString(JSONObject jo) throws JSONException {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { if (jo.has("Status-Code") && jo.has("Reason-Phrase")) {
sb.append(jo.getString("HTTP-Version")); sb.append(jo.getString("HTTP-Version"));
sb.append(' '); sb.append(' ');
@ -147,9 +152,9 @@ public class HTTP {
// Don't use the new entrySet API to maintain Android support // Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) { for (final String key : jo.keySet()) {
String value = jo.optString(key); String value = jo.optString(key);
if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) && if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) &&
!"Reason-Phrase".equals(key) && !"Method".equals(key) && !"Reason-Phrase".equals(key) && !"Method".equals(key) &&
!"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) { !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) {
sb.append(key); sb.append(key);
sb.append(": "); sb.append(": ");
sb.append(jo.optString(key)); sb.append(jo.optString(key));

View File

@ -27,6 +27,7 @@ SOFTWARE.
/** /**
* The HTTPTokener extends the JSONTokener to provide additional methods * The HTTPTokener extends the JSONTokener to provide additional methods
* for the parsing of HTTP headers. * for the parsing of HTTP headers.
*
* @author JSON.org * @author JSON.org
* @version 2015-12-09 * @version 2015-12-09
*/ */
@ -34,6 +35,7 @@ public class HTTPTokener extends JSONTokener {
/** /**
* Construct an HTTPTokener from a string. * Construct an HTTPTokener from a string.
*
* @param string A source string. * @param string A source string.
*/ */
public HTTPTokener(String string) { public HTTPTokener(String string) {
@ -43,8 +45,9 @@ public class HTTPTokener extends JSONTokener {
/** /**
* Get the next token or string. This is used in parsing HTTP headers. * Get the next token or string. This is used in parsing HTTP headers.
* @throws JSONException *
* @return A String. * @return A String.
* @throws JSONException
*/ */
public String nextToken() throws JSONException { public String nextToken() throws JSONException {
char c; char c;
@ -55,7 +58,7 @@ public class HTTPTokener extends JSONTokener {
} while (Character.isWhitespace(c)); } while (Character.isWhitespace(c));
if (c == '"' || c == '\'') { if (c == '"' || c == '\'') {
q = c; q = c;
for (;;) { for (; ; ) {
c = next(); c = next();
if (c < ' ') { if (c < ' ') {
throw syntaxError("Unterminated string."); throw syntaxError("Unterminated string.");
@ -66,7 +69,7 @@ public class HTTPTokener extends JSONTokener {
sb.append(c); sb.append(c);
} }
} }
for (;;) { for (; ; ) {
if (c == 0 || Character.isWhitespace(c)) { if (c == 0 || Character.isWhitespace(c)) {
return sb.toString(); return sb.toString();
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,14 +7,15 @@ package ch.m4th1eu.json;
* @version 2015-12-09 * @version 2015-12-09
*/ */
public class JSONException extends RuntimeException { public class JSONException extends RuntimeException {
/** Serialization ID */ /**
* Serialization ID
*/
private static final long serialVersionUID = 0; private static final long serialVersionUID = 0;
/** /**
* Constructs a JSONException with an explanatory message. * Constructs a JSONException with an explanatory message.
* *
* @param message * @param message Detail about the reason for the exception.
* Detail about the reason for the exception.
*/ */
public JSONException(final String message) { public JSONException(final String message) {
super(message); super(message);
@ -23,10 +24,8 @@ public class JSONException extends RuntimeException {
/** /**
* Constructs a JSONException with an explanatory message and cause. * Constructs a JSONException with an explanatory message and cause.
* *
* @param message * @param message Detail about the reason for the exception.
* Detail about the reason for the exception. * @param cause The cause.
* @param cause
* The cause.
*/ */
public JSONException(final String message, final Throwable cause) { public JSONException(final String message, final Throwable cause) {
super(message, cause); super(message, cause);
@ -35,8 +34,7 @@ public class JSONException extends RuntimeException {
/** /**
* Constructs a new JSONException with the specified cause. * Constructs a new JSONException with the specified cause.
* *
* @param cause * @param cause The cause.
* The cause.
*/ */
public JSONException(final Throwable cause) { public JSONException(final Throwable cause) {
super(cause.getMessage(), cause); super(cause.getMessage(), cause);

View File

@ -35,28 +35,29 @@ SOFTWARE.
public class JSONML { public class JSONML {
/** /**
* Parse XML values and store them in a JSONArray. * 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 x The XMLTokener containing the source string.
* @param ja The JSONArray that is containing the current tag or null * @param arrayForm true if array form, false if object form.
* if we are at the outermost level. * @param ja The JSONArray that is containing the current tag or null
* @param keepStrings Don't type-convert text nodes and attribute values * if we are at the outermost level.
* @param keepStrings Don't type-convert text nodes and attribute values
* @return A JSONArray if the value is the outermost tag, otherwise null. * @return A JSONArray if the value is the outermost tag, otherwise null.
* @throws JSONException * @throws JSONException
*/ */
private static Object parse( private static Object parse(
XMLTokener x, XMLTokener x,
boolean arrayForm, boolean arrayForm,
JSONArray ja, JSONArray ja,
boolean keepStrings boolean keepStrings
) throws JSONException { ) throws JSONException {
String attribute; String attribute;
char c; char c;
String closeTag = null; String closeTag = null;
int i; int i;
JSONArray newja = null; JSONArray newja = null;
JSONObject newjo = null; JSONObject newjo = null;
Object token; Object token;
String tagName = null; String tagName = null;
// Test for and skip past these forms: // Test for and skip past these forms:
// <!-- ... --> // <!-- ... -->
@ -80,7 +81,7 @@ public class JSONML {
if (!(token instanceof String)) { if (!(token instanceof String)) {
throw new JSONException( throw new JSONException(
"Expected a closing name instead of '" + "Expected a closing name instead of '" +
token + "'."); token + "'.");
} }
if (x.nextToken() != XML.GT) { if (x.nextToken() != XML.GT) {
throw x.syntaxError("Misshaped close tag"); throw x.syntaxError("Misshaped close tag");
@ -134,7 +135,7 @@ public class JSONML {
if (!(token instanceof String)) { if (!(token instanceof String)) {
throw x.syntaxError("Bad tagName '" + token + "'."); throw x.syntaxError("Bad tagName '" + token + "'.");
} }
tagName = (String)token; tagName = (String) token;
newja = new JSONArray(); newja = new JSONArray();
newjo = new JSONObject(); newjo = new JSONObject();
if (arrayForm) { if (arrayForm) {
@ -149,7 +150,7 @@ public class JSONML {
} }
} }
token = null; token = null;
for (;;) { for (; ; ) {
if (token == null) { if (token == null) {
token = x.nextToken(); token = x.nextToken();
} }
@ -162,7 +163,7 @@ public class JSONML {
// attribute = value // attribute = value
attribute = (String)token; attribute = (String) token;
if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {
throw x.syntaxError("Reserved attribute."); throw x.syntaxError("Reserved attribute.");
} }
@ -172,7 +173,7 @@ public class JSONML {
if (!(token instanceof String)) { if (!(token instanceof String)) {
throw x.syntaxError("Missing value"); throw x.syntaxError("Missing value");
} }
newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token)); newjo.accumulate(attribute, keepStrings ? ((String) token) : XML.stringToValue((String) token));
token = null; token = null;
} else { } else {
newjo.accumulate(attribute, ""); newjo.accumulate(attribute, "");
@ -201,7 +202,7 @@ public class JSONML {
if (token != XML.GT) { if (token != XML.GT) {
throw x.syntaxError("Misshaped tag"); throw x.syntaxError("Misshaped tag");
} }
closeTag = (String)parse(x, arrayForm, newja, keepStrings); closeTag = (String) parse(x, arrayForm, newja, keepStrings);
if (closeTag != null) { if (closeTag != null) {
if (!closeTag.equals(tagName)) { if (!closeTag.equals(tagName)) {
throw x.syntaxError("Mismatched '" + tagName + throw x.syntaxError("Mismatched '" + tagName +
@ -223,8 +224,8 @@ public class JSONML {
} else { } else {
if (ja != null) { if (ja != null) {
ja.put(token instanceof String ja.put(token instanceof String
? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token) ? keepStrings ? XML.unescape((String) token) : XML.stringToValue((String) token)
: token); : token);
} }
} }
} }
@ -239,12 +240,13 @@ public class JSONML {
* name/value pairs. If the tag contains children, then strings and * name/value pairs. If the tag contains children, then strings and
* JSONArrays will represent the child tags. * JSONArrays will represent the child tags.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored. * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
*
* @param string The source string. * @param string The source string.
* @return A JSONArray containing the structured data from the XML string. * @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray * @throws JSONException Thrown on error converting to a JSONArray
*/ */
public static JSONArray toJSONArray(String string) throws JSONException { public static JSONArray toJSONArray(String string) throws JSONException {
return (JSONArray)parse(new XMLTokener(string), true, null, false); return (JSONArray) parse(new XMLTokener(string), true, null, false);
} }
@ -259,14 +261,15 @@ public class JSONML {
* any text node or attribute value to any type * any text node or attribute value to any type
* but just leaves it as a string. * but just leaves it as a string.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored. * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The source string. *
* @param string The source string.
* @param keepStrings If true, then values will not be coerced into boolean * @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings * or numeric values and will instead be left as strings
* @return A JSONArray containing the structured data from the XML string. * @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray * @throws JSONException Thrown on error converting to a JSONArray
*/ */
public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException {
return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); return (JSONArray) parse(new XMLTokener(string), true, null, keepStrings);
} }
@ -281,14 +284,15 @@ public class JSONML {
* any text node or attribute value to any type * any text node or attribute value to any type
* but just leaves it as a string. * but just leaves it as a string.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored. * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener. *
* @param x An XMLTokener.
* @param keepStrings If true, then values will not be coerced into boolean * @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings * or numeric values and will instead be left as strings
* @return A JSONArray containing the structured data from the XML string. * @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray * @throws JSONException Thrown on error converting to a JSONArray
*/ */
public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException {
return (JSONArray)parse(x, true, null, keepStrings); return (JSONArray) parse(x, true, null, keepStrings);
} }
@ -300,12 +304,13 @@ public class JSONML {
* name/value pairs. If the tag contains children, then strings and * name/value pairs. If the tag contains children, then strings and
* JSONArrays will represent the child content and tags. * JSONArrays will represent the child content and tags.
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored. * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
*
* @param x An XMLTokener. * @param x An XMLTokener.
* @return A JSONArray containing the structured data from the XML string. * @return A JSONArray containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONArray * @throws JSONException Thrown on error converting to a JSONArray
*/ */
public static JSONArray toJSONArray(XMLTokener x) throws JSONException { public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
return (JSONArray)parse(x, true, null, false); return (JSONArray) parse(x, true, null, false);
} }
@ -316,14 +321,15 @@ public class JSONML {
* the attributes will be in the JSONObject as properties. If the tag * the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which * contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects. * will be an array of strings and JsonML JSONObjects.
* <p>
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored. * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
*
* @param string The XML source text. * @param string The XML source text.
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject * @throws JSONException Thrown on error converting to a JSONObject
*/ */
public static JSONObject toJSONObject(String string) throws JSONException { public static JSONObject toJSONObject(String string) throws JSONException {
return (JSONObject)parse(new XMLTokener(string), false, null, false); return (JSONObject) parse(new XMLTokener(string), false, null, false);
} }
@ -334,16 +340,17 @@ public class JSONML {
* the attributes will be in the JSONObject as properties. If the tag * the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which * contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects. * will be an array of strings and JsonML JSONObjects.
* <p>
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored. * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param string The XML source text. *
* @param string The XML source text.
* @param keepStrings If true, then values will not be coerced into boolean * @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings * or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject * @throws JSONException Thrown on error converting to a JSONObject
*/ */
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); return (JSONObject) parse(new XMLTokener(string), false, null, keepStrings);
} }
@ -354,14 +361,15 @@ public class JSONML {
* the attributes will be in the JSONObject as properties. If the tag * the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which * contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects. * will be an array of strings and JsonML JSONObjects.
* <p>
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored. * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
*
* @param x An XMLTokener of the XML source text. * @param x An XMLTokener of the XML source text.
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject * @throws JSONException Thrown on error converting to a JSONObject
*/ */
public static JSONObject toJSONObject(XMLTokener x) throws JSONException { public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
return (JSONObject)parse(x, false, null, false); return (JSONObject) parse(x, false, null, false);
} }
@ -372,32 +380,34 @@ public class JSONML {
* the attributes will be in the JSONObject as properties. If the tag * the attributes will be in the JSONObject as properties. If the tag
* contains children, the object will have a "childNodes" property which * contains children, the object will have a "childNodes" property which
* will be an array of strings and JsonML JSONObjects. * will be an array of strings and JsonML JSONObjects.
* <p>
* Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored. * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
* @param x An XMLTokener of the XML source text. *
* @param x An XMLTokener of the XML source text.
* @param keepStrings If true, then values will not be coerced into boolean * @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings * or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown on error converting to a JSONObject * @throws JSONException Thrown on error converting to a JSONObject
*/ */
public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException {
return (JSONObject)parse(x, false, null, keepStrings); return (JSONObject) parse(x, false, null, keepStrings);
} }
/** /**
* Reverse the JSONML transformation, making an XML text from a JSONArray. * Reverse the JSONML transformation, making an XML text from a JSONArray.
*
* @param ja A JSONArray. * @param ja A JSONArray.
* @return An XML string. * @return An XML string.
* @throws JSONException Thrown on error converting to a string * @throws JSONException Thrown on error converting to a string
*/ */
public static String toString(JSONArray ja) throws JSONException { public static String toString(JSONArray ja) throws JSONException {
int i; int i;
JSONObject jo; JSONObject jo;
int length; int length;
Object object; Object object;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
String tagName; String tagName;
// Emit <tagName // Emit <tagName
@ -410,7 +420,7 @@ public class JSONML {
object = ja.opt(1); object = ja.opt(1);
if (object instanceof JSONObject) { if (object instanceof JSONObject) {
i = 2; i = 2;
jo = (JSONObject)object; jo = (JSONObject) object;
// Emit the attributes // Emit the attributes
@ -446,9 +456,9 @@ public class JSONML {
if (object instanceof String) { if (object instanceof String) {
sb.append(XML.escape(object.toString())); sb.append(XML.escape(object.toString()));
} else if (object instanceof JSONObject) { } else if (object instanceof JSONObject) {
sb.append(toString((JSONObject)object)); sb.append(toString((JSONObject) object));
} else if (object instanceof JSONArray) { } else if (object instanceof JSONArray) {
sb.append(toString((JSONArray)object)); sb.append(toString((JSONArray) object));
} else { } else {
sb.append(object.toString()); sb.append(object.toString());
} }
@ -467,18 +477,19 @@ public class JSONML {
* The JSONObject must contain a "tagName" property. If it has children, * The JSONObject must contain a "tagName" property. If it has children,
* then it must have a "childNodes" property containing an array of objects. * then it must have a "childNodes" property containing an array of objects.
* The other properties are attributes with string values. * The other properties are attributes with string values.
*
* @param jo A JSONObject. * @param jo A JSONObject.
* @return An XML string. * @return An XML string.
* @throws JSONException Thrown on error converting to a string * @throws JSONException Thrown on error converting to a string
*/ */
public static String toString(JSONObject jo) throws JSONException { public static String toString(JSONObject jo) throws JSONException {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int i; int i;
JSONArray ja; JSONArray ja;
int length; int length;
Object object; Object object;
String tagName; String tagName;
Object value; Object value;
//Emit <tagName //Emit <tagName
@ -524,9 +535,9 @@ public class JSONML {
if (object instanceof String) { if (object instanceof String) {
sb.append(XML.escape(object.toString())); sb.append(XML.escape(object.toString()));
} else if (object instanceof JSONObject) { } else if (object instanceof JSONObject) {
sb.append(toString((JSONObject)object)); sb.append(toString((JSONObject) object));
} else if (object instanceof JSONArray) { } else if (object instanceof JSONArray) {
sb.append(toString((JSONArray)object)); sb.append(toString((JSONArray) object));
} else { } else {
sb.append(object.toString()); sb.append(object.toString());
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,5 @@
package ch.m4th1eu.json; package ch.m4th1eu.json;
import static java.lang.String.format;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
@ -9,6 +7,8 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static java.lang.String.format;
/* /*
Copyright (c) 2002 JSON.org Copyright (c) 2002 JSON.org
@ -36,7 +36,7 @@ SOFTWARE.
/** /**
* A JSON Pointer is a simple query language defined for JSON documents by * A JSON Pointer is a simple query language defined for JSON documents by
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>. * <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
* * <p>
* In a nutshell, JSONPointer allows the user to navigate into a JSON document * 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. * using strings, and retrieve targeted objects, like a simple form of XPATH.
* Path segments are separated by the '/' char, which signifies the root of * Path segments are separated by the '/' char, which signifies the root of
@ -55,76 +55,6 @@ public class JSONPointer {
// used for URL encoding and decoding // used for URL encoding and decoding
private static final String ENCODING = "utf-8"; 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(this.refTokens);
}
/**
* Adds an arbitrary 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");
}
this.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) {
this.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 // Segments for the JSONPointer string
private final List<String> refTokens; private final List<String> refTokens;
@ -163,7 +93,7 @@ public class JSONPointer {
do { do {
prevSlashIdx = slashIdx + 1; prevSlashIdx = slashIdx + 1;
slashIdx = refs.indexOf('/', prevSlashIdx); slashIdx = refs.indexOf('/', prevSlashIdx);
if(prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) { if (prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) {
// found 2 slashes in a row ( obj//next ) // found 2 slashes in a row ( obj//next )
// or single slash at the end of a string ( obj/test/ ) // or single slash at the end of a string ( obj/test/ )
this.refTokens.add(""); this.refTokens.add("");
@ -186,6 +116,25 @@ public class JSONPointer {
this.refTokens = new ArrayList<String>(refTokens); this.refTokens = new ArrayList<String>(refTokens);
} }
/**
* 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();
}
private String unescape(String token) { private String unescape(String token) {
return token.replace("~1", "/").replace("~0", "~") return token.replace("~1", "/").replace("~0", "~")
.replace("\\\"", "\"") .replace("\\\"", "\"")
@ -223,7 +172,8 @@ public class JSONPointer {
/** /**
* Matches a JSONArray element by ordinal position * Matches a JSONArray element by ordinal position
* @param current the JSONArray to be evaluated *
* @param current the JSONArray to be evaluated
* @param indexToken the array index in string form * @param indexToken the array index in string form
* @return the matched object. If no matching item is found a * @return the matched object. If no matching item is found a
* @throws JSONPointerException is thrown if the index is out of bounds * @throws JSONPointerException is thrown if the index is out of bounds
@ -237,10 +187,10 @@ public class JSONPointer {
Integer.valueOf(currentArr.length()))); Integer.valueOf(currentArr.length())));
} }
try { try {
return currentArr.get(index); return currentArr.get(index);
} catch (JSONException e) { } catch (JSONException e) {
throw new JSONPointerException("Error reading value at index position " + index, e); throw new JSONPointerException("Error reading value at index position " + index, e);
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new JSONPointerException(format("%s is not an array index", indexToken), e); throw new JSONPointerException(format("%s is not an array index", indexToken), e);
} }
@ -252,8 +202,8 @@ public class JSONPointer {
*/ */
@Override @Override
public String toString() { public String toString() {
StringBuilder rval = new StringBuilder(""); StringBuilder rval = new StringBuilder();
for (String token: this.refTokens) { for (String token : this.refTokens) {
rval.append('/').append(escape(token)); rval.append('/').append(escape(token));
} }
return rval.toString(); return rval.toString();
@ -264,6 +214,7 @@ public class JSONPointer {
* The escape char to be inserted is '~'. The chars to be escaped * The escape char to be inserted is '~'. The chars to be escaped
* are ~, which maps to ~0, and /, which maps to ~1. Backslashes * are ~, which maps to ~0, and /, which maps to ~1. Backslashes
* and double quote chars are also escaped. * and double quote chars are also escaped.
*
* @param token the JSONPointer segment value to be escaped * @param token the JSONPointer segment value to be escaped
* @return the escaped value for the token * @return the escaped value for the token
*/ */
@ -290,4 +241,54 @@ public class JSONPointer {
} }
} }
/**
* 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(this.refTokens);
}
/**
* Adds an arbitrary token to the list of reference tokens. It can be any non-null value.
* <p>
* 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");
}
this.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) {
this.refTokens.add(String.valueOf(arrayIndex));
return this;
}
}
} }

View File

@ -24,13 +24,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented @Documented
@Retention(RUNTIME) @Retention(RUNTIME)
@Target({METHOD}) @Target({METHOD})
@ -40,4 +40,5 @@ import java.lang.annotation.Target;
* present at any level in the class hierarchy, then the method will * present at any level in the class hierarchy, then the method will
* not be serialized from the bean into the JSONObject. * not be serialized from the bean into the JSONObject.
*/ */
public @interface JSONPropertyIgnore { } public @interface JSONPropertyIgnore {
}

View File

@ -24,13 +24,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented @Documented
@Retention(RUNTIME) @Retention(RUNTIME)
@Target({METHOD}) @Target({METHOD})

View File

@ -1,4 +1,5 @@
package ch.m4th1eu.json; package ch.m4th1eu.json;
/** /**
* The <code>JSONString</code> interface allows a <code>toJSONString()</code> * The <code>JSONString</code> interface allows a <code>toJSONString()</code>
* method so that a class can change the behavior of * method so that a class can change the behavior of
@ -14,5 +15,5 @@ public interface JSONString {
* *
* @return A strictly syntactically correct JSON text. * @return A strictly syntactically correct JSON text.
*/ */
public String toJSONString(); String toJSONString();
} }

View File

@ -53,6 +53,7 @@ import java.io.StringWriter;
* you. Objects and arrays can be nested up to 20 levels deep. * you. Objects and arrays can be nested up to 20 levels deep.
* <p> * <p>
* This can sometimes be easier than using a JSONObject to build a string. * This can sometimes be easier than using a JSONObject to build a string.
*
* @author JSON.org * @author JSON.org
* @version 2015-12-09 * @version 2015-12-09
*/ */
@ -70,6 +71,7 @@ public class JSONStringer extends JSONWriter {
* problem in the construction of the JSON text (such as the calls to * problem in the construction of the JSON text (such as the calls to
* <code>array</code> were not properly balanced with calls to * <code>array</code> were not properly balanced with calls to
* <code>endArray</code>). * <code>endArray</code>).
*
* @return The JSON text. * @return The JSON text.
*/ */
@Override @Override

View File

@ -1,11 +1,6 @@
package ch.m4th1eu.json; package ch.m4th1eu.json;
import java.io.BufferedReader; import java.io.*;
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 Copyright (c) 2002 JSON.org
@ -35,37 +30,54 @@ SOFTWARE.
* A JSONTokener takes a source string and extracts characters and tokens from * A JSONTokener takes a source string and extracts characters and tokens from
* it. It is used by the JSONObject and JSONArray constructors to parse * it. It is used by the JSONObject and JSONArray constructors to parse
* JSON source strings. * JSON source strings.
*
* @author JSON.org * @author JSON.org
* @version 2014-05-03 * @version 2014-05-03
*/ */
public class JSONTokener { public class JSONTokener {
/** current read character position on the current line. */ /**
private long character; * Reader for the input.
/** flag to indicate if the end of the input has been found. */ */
private boolean eof;
/** current read index of the input. */
private long index;
/** current line of the input. */
private long line;
/** previous character read from the input. */
private char previous;
/** Reader for the input. */
private final Reader reader; private final Reader reader;
/** flag to indicate that a previous character was requested. */ /**
* current read character position on the current line.
*/
private long character;
/**
* flag to indicate if the end of the input has been found.
*/
private boolean eof;
/**
* current read index of the input.
*/
private long index;
/**
* current line of the input.
*/
private long line;
/**
* previous character read from the input.
*/
private char previous;
/**
* flag to indicate that a previous character was requested.
*/
private boolean usePrevious; private boolean usePrevious;
/** the number of characters read in the previous line. */ /**
* the number of characters read in the previous line.
*/
private long characterPreviousLine; private long characterPreviousLine;
/** /**
* Construct a JSONTokener from a Reader. The caller must close the Reader. * Construct a JSONTokener from a Reader. The caller must close the Reader.
* *
* @param reader A reader. * @param reader A reader.
*/ */
public JSONTokener(Reader reader) { public JSONTokener(Reader reader) {
this.reader = reader.markSupported() this.reader = reader.markSupported()
? reader ? reader
: new BufferedReader(reader); : new BufferedReader(reader);
this.eof = false; this.eof = false;
this.usePrevious = false; this.usePrevious = false;
this.previous = 0; this.previous = 0;
@ -78,6 +90,7 @@ public class JSONTokener {
/** /**
* Construct a JSONTokener from an InputStream. The caller must close the input stream. * Construct a JSONTokener from an InputStream. The caller must close the input stream.
*
* @param inputStream The source. * @param inputStream The source.
*/ */
public JSONTokener(InputStream inputStream) { public JSONTokener(InputStream inputStream) {
@ -88,47 +101,18 @@ public class JSONTokener {
/** /**
* Construct a JSONTokener from a string. * Construct a JSONTokener from a string.
* *
* @param s A source string. * @param s A source string.
*/ */
public JSONTokener(String s) { public JSONTokener(String s) {
this(new StringReader(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.decrementIndexes();
this.usePrevious = true;
this.eof = false;
}
/**
* Decrements the indexes for the {@link #back()} method based on the previous character read.
*/
private void decrementIndexes() {
this.index--;
if(this.previous=='\r' || this.previous == '\n') {
this.line--;
this.character=this.characterPreviousLine ;
} else if(this.character > 0){
this.character--;
}
}
/** /**
* Get the hex value of a character (base16). * Get the hex value of a character (base16).
*
* @param c A character between '0' and '9' or between 'A' and 'F' or * @param c A character between '0' and '9' or between 'A' and 'F' or
* between 'a' and 'f'. * between 'a' and 'f'.
* @return An int between 0 and 15, or -1 if c was not a hex digit. * @return An int between 0 and 15, or -1 if c was not a hex digit.
*/ */
public static int dehexchar(char c) { public static int dehexchar(char c) {
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
@ -143,6 +127,36 @@ public class JSONTokener {
return -1; return -1;
} }
/**
* 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.decrementIndexes();
this.usePrevious = true;
this.eof = false;
}
/**
* Decrements the indexes for the {@link #back()} method based on the previous character read.
*/
private void decrementIndexes() {
this.index--;
if (this.previous == '\r' || this.previous == '\n') {
this.line--;
this.character = this.characterPreviousLine;
} else if (this.character > 0) {
this.character--;
}
}
/** /**
* Checks if the end of the input has been reached. * Checks if the end of the input has been reached.
* *
@ -156,12 +170,13 @@ public class JSONTokener {
/** /**
* Determine if the source string still contains characters that next() * Determine if the source string still contains characters that next()
* can consume. * can consume.
*
* @return true if not yet at the end of the source. * @return true if not yet at the end of the source.
* @throws JSONException thrown if there is an error stepping forward * @throws JSONException thrown if there is an error stepping forward
* or backward while checking for more data. * or backward while checking for more data.
*/ */
public boolean more() throws JSONException { public boolean more() throws JSONException {
if(this.usePrevious) { if (this.usePrevious) {
return true; return true;
} }
try { try {
@ -171,7 +186,7 @@ public class JSONTokener {
} }
try { try {
// -1 is EOF, but next() can not consume the null character '\0' // -1 is EOF, but next() can not consume the null character '\0'
if(this.reader.read() <= 0) { if (this.reader.read() <= 0) {
this.eof = true; this.eof = true;
return false; return false;
} }
@ -213,21 +228,22 @@ public class JSONTokener {
/** /**
* Increments the internal indexes according to the previous character * Increments the internal indexes according to the previous character
* read and the character passed as the current character. * read and the character passed as the current character.
*
* @param c the current character read. * @param c the current character read.
*/ */
private void incrementIndexes(int c) { private void incrementIndexes(int c) {
if(c > 0) { if (c > 0) {
this.index++; this.index++;
if(c=='\r') { if (c == '\r') {
this.line++; this.line++;
this.characterPreviousLine = this.character; this.characterPreviousLine = this.character;
this.character=0; this.character = 0;
}else if (c=='\n') { } else if (c == '\n') {
if(this.previous != '\r') { if (this.previous != '\r') {
this.line++; this.line++;
this.characterPreviousLine = this.character; this.characterPreviousLine = this.character;
} }
this.character=0; this.character = 0;
} else { } else {
this.character++; this.character++;
} }
@ -237,6 +253,7 @@ public class JSONTokener {
/** /**
* Consume the next character, and check that it matches a specified * Consume the next character, and check that it matches a specified
* character. * character.
*
* @param c The character to match. * @param c The character to match.
* @return The character. * @return The character.
* @throws JSONException if the character does not match. * @throws JSONException if the character does not match.
@ -244,7 +261,7 @@ public class JSONTokener {
public char next(char c) throws JSONException { public char next(char c) throws JSONException {
char n = this.next(); char n = this.next();
if (n != c) { if (n != c) {
if(n > 0) { if (n > 0) {
throw this.syntaxError("Expected '" + c + "' and instead saw '" + throw this.syntaxError("Expected '" + c + "' and instead saw '" +
n + "'"); n + "'");
} }
@ -257,11 +274,10 @@ public class JSONTokener {
/** /**
* Get the next n characters. * Get the next n characters.
* *
* @param n The number of characters to take. * @param n The number of characters to take.
* @return A string of n characters. * @return A string of n characters.
* @throws JSONException * @throws JSONException Substring bounds error if there are not
* Substring bounds error if there are not * n characters remaining in the source string.
* n characters remaining in the source string.
*/ */
public String next(int n) throws JSONException { public String next(int n) throws JSONException {
if (n == 0) { if (n == 0) {
@ -284,11 +300,12 @@ public class JSONTokener {
/** /**
* Get the next char in the string, skipping whitespace. * Get the next char in the string, skipping whitespace.
*
* @return A character, or 0 if there are no more characters.
* @throws JSONException Thrown if there is an error reading the source string. * @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 { public char nextClean() throws JSONException {
for (;;) { for (; ; ) {
char c = this.next(); char c = this.next();
if (c == 0 || c > ' ') { if (c == 0 || c > ' ') {
return c; return c;
@ -302,62 +319,63 @@ public class JSONTokener {
* Backslash processing is done. The formal JSON format does not * Backslash processing is done. The formal JSON format does not
* allow strings in single quotes, but an implementation is allowed to * allow strings in single quotes, but an implementation is allowed to
* accept them. * accept them.
*
* @param quote The quoting character, either * @param quote The quoting character, either
* <code>"</code>&nbsp;<small>(double quote)</small> or * <code>"</code>&nbsp;<small>(double quote)</small> or
* <code>'</code>&nbsp;<small>(single quote)</small>. * <code>'</code>&nbsp;<small>(single quote)</small>.
* @return A String. * @return A String.
* @throws JSONException Unterminated string. * @throws JSONException Unterminated string.
*/ */
public String nextString(char quote) throws JSONException { public String nextString(char quote) throws JSONException {
char c; char c;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (;;) { for (; ; ) {
c = this.next(); c = this.next();
switch (c) { switch (c) {
case 0: case 0:
case '\n': case '\n':
case '\r': case '\r':
throw this.syntaxError("Unterminated string"); throw this.syntaxError("Unterminated string");
case '\\': case '\\':
c = this.next(); c = this.next();
switch (c) { switch (c) {
case 'b': case 'b':
sb.append('\b'); sb.append('\b');
break; break;
case 't': case 't':
sb.append('\t'); sb.append('\t');
break; break;
case 'n': case 'n':
sb.append('\n'); sb.append('\n');
break; break;
case 'f': case 'f':
sb.append('\f'); sb.append('\f');
break; break;
case 'r': case 'r':
sb.append('\r'); sb.append('\r');
break; break;
case 'u': case 'u':
try { try {
sb.append((char)Integer.parseInt(this.next(4), 16)); sb.append((char) Integer.parseInt(this.next(4), 16));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw this.syntaxError("Illegal escape.", e); throw this.syntaxError("Illegal escape.", e);
}
break;
case '"':
case '\'':
case '\\':
case '/':
sb.append(c);
break;
default:
throw this.syntaxError("Illegal escape.");
} }
break; break;
case '"':
case '\'':
case '\\':
case '/':
sb.append(c);
break;
default: default:
throw this.syntaxError("Illegal escape."); if (c == quote) {
} return sb.toString();
break; }
default: sb.append(c);
if (c == quote) {
return sb.toString();
}
sb.append(c);
} }
} }
} }
@ -366,14 +384,15 @@ public class JSONTokener {
/** /**
* Get the text up but not including the specified character or the * Get the text up but not including the specified character or the
* end of line, whichever comes first. * end of line, whichever comes first.
* @param delimiter A delimiter character. *
* @return A string. * @param delimiter A delimiter character.
* @return A string.
* @throws JSONException Thrown if there is an error while searching * @throws JSONException Thrown if there is an error while searching
* for the delimiter * for the delimiter
*/ */
public String nextTo(char delimiter) throws JSONException { public String nextTo(char delimiter) throws JSONException {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (;;) { for (; ; ) {
char c = this.next(); char c = this.next();
if (c == delimiter || c == 0 || c == '\n' || c == '\r') { if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
if (c != 0) { if (c != 0) {
@ -389,15 +408,16 @@ public class JSONTokener {
/** /**
* Get the text up but not including one of the specified delimiter * Get the text up but not including one of the specified delimiter
* characters or the end of line, whichever comes first. * characters or the end of line, whichever comes first.
*
* @param delimiters A set of delimiter characters. * @param delimiters A set of delimiter characters.
* @return A string, trimmed. * @return A string, trimmed.
* @throws JSONException Thrown if there is an error while searching * @throws JSONException Thrown if there is an error while searching
* for the delimiter * for the delimiter
*/ */
public String nextTo(String delimiters) throws JSONException { public String nextTo(String delimiters) throws JSONException {
char c; char c;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (;;) { for (; ; ) {
c = this.next(); c = this.next();
if (delimiters.indexOf(c) >= 0 || c == 0 || if (delimiters.indexOf(c) >= 0 || c == 0 ||
c == '\n' || c == '\r') { c == '\n' || c == '\r') {
@ -414,24 +434,24 @@ public class JSONTokener {
/** /**
* Get the next value. The value can be a Boolean, Double, Integer, * Get the next value. The value can be a Boolean, Double, Integer,
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
* @throws JSONException If syntax error.
* *
* @return An object. * @return An object.
* @throws JSONException If syntax error.
*/ */
public Object nextValue() throws JSONException { public Object nextValue() throws JSONException {
char c = this.nextClean(); char c = this.nextClean();
String string; String string;
switch (c) { switch (c) {
case '"': case '"':
case '\'': case '\'':
return this.nextString(c); return this.nextString(c);
case '{': case '{':
this.back(); this.back();
return new JSONObject(this); return new JSONObject(this);
case '[': case '[':
this.back(); this.back();
return new JSONArray(this); return new JSONArray(this);
} }
/* /*
@ -463,11 +483,12 @@ public class JSONTokener {
/** /**
* Skip characters until the next character is the requested character. * Skip characters until the next character is the requested character.
* If the requested character is not found, no characters are skipped. * If the requested character is not found, no characters are skipped.
*
* @param to A character to skip to. * @param to A character to skip to.
* @return The requested character, or zero if the requested character * @return The requested character, or zero if the requested character
* is not found. * is not found.
* @throws JSONException Thrown if there is an error while searching * @throws JSONException Thrown if there is an error while searching
* for the to character * for the to character
*/ */
public char skipTo(char to) throws JSONException { public char skipTo(char to) throws JSONException {
char c; char c;
@ -501,7 +522,7 @@ public class JSONTokener {
* Make a JSONException to signal a syntax error. * Make a JSONException to signal a syntax error.
* *
* @param message The error message. * @param message The error message.
* @return A JSONException object, suitable for throwing * @return A JSONException object, suitable for throwing
*/ */
public JSONException syntaxError(String message) { public JSONException syntaxError(String message) {
return new JSONException(message + this.toString()); return new JSONException(message + this.toString());
@ -510,9 +531,9 @@ public class JSONTokener {
/** /**
* Make a JSONException to signal a syntax error. * Make a JSONException to signal a syntax error.
* *
* @param message The error message. * @param message The error message.
* @param causedBy The throwable that caused the error. * @param causedBy The throwable that caused the error.
* @return A JSONException object, suitable for throwing * @return A JSONException object, suitable for throwing
*/ */
public JSONException syntaxError(String message, Throwable causedBy) { public JSONException syntaxError(String message, Throwable causedBy) {
return new JSONException(message + this.toString(), causedBy); return new JSONException(message + this.toString(), causedBy);

View File

@ -54,18 +54,16 @@ SOFTWARE.
* you. Objects and arrays can be nested up to 200 levels deep. * you. Objects and arrays can be nested up to 200 levels deep.
* <p> * <p>
* This can sometimes be easier than using a JSONObject to build a string. * This can sometimes be easier than using a JSONObject to build a string.
*
* @author JSON.org * @author JSON.org
* @version 2016-08-08 * @version 2016-08-08
*/ */
public class JSONWriter { public class JSONWriter {
private static final int maxdepth = 200; private static final int maxdepth = 200;
/** /**
* The comma flag determines if a comma should be output before the next * The object/array stack.
* value.
*/ */
private boolean comma; private final JSONObject[] stack;
/** /**
* The current mode. Values: * The current mode. Values:
* 'a' (array), * 'a' (array),
@ -75,21 +73,19 @@ public class JSONWriter {
* 'o' (object). * 'o' (object).
*/ */
protected char mode; 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. * The writer that will receive the output.
*/ */
protected Appendable writer; protected Appendable writer;
/**
* The comma flag determines if a comma should be output before the next
* value.
*/
private boolean comma;
/**
* The stack top index. A value of 0 indicates that the stack is empty.
*/
private int top;
/** /**
* Make a fresh JSONWriter. It can be used to build one JSON text. * Make a fresh JSONWriter. It can be used to build one JSON text.
@ -102,200 +98,6 @@ public class JSONWriter {
this.writer = w; 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) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
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 m Mode
* @param c Closing character
* @return this
* @throws JSONException If unbalanced.
*/
private JSONWriter end(char m, char c) throws JSONException {
if (this.mode != m) {
throw new JSONException(m == 'a'
? "Misplaced endArray."
: "Misplaced endObject.");
}
this.pop(m);
try {
this.writer.append(c);
} catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
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 {
JSONObject topObject = this.stack[this.top - 1];
// don't use the built in putOnce method to maintain Android support
if(topObject.has(string)) {
throw new JSONException("Duplicate key \"" + string + "\"");
}
topObject.put(string, 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) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
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;
}
/** /**
* Make a JSON text of an Object value. If the object has an * Make a JSON text of an Object value. If the object has an
* value.toJSONString() method, then that method will be used to produce the * value.toJSONString() method, then that method will be used to produce the
@ -311,14 +113,12 @@ public class JSONWriter {
* <p> * <p>
* Warning: This method assumes that the data structure is acyclical. * Warning: This method assumes that the data structure is acyclical.
* *
* @param value * @param value The value to be serialized.
* The value to be serialized.
* @return a printable, displayable, transmittable representation of the * @return a printable, displayable, transmittable representation of the
* object, beginning with <code>{</code>&nbsp;<small>(left * object, beginning with <code>{</code>&nbsp;<small>(left
* brace)</small> and ending with <code>}</code>&nbsp;<small>(right * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
* brace)</small>. * brace)</small>.
* @throws JSONException * @throws JSONException If the value is or contains an invalid number.
* If the value is or contains an invalid number.
*/ */
public static String valueToString(Object value) throws JSONException { public static String valueToString(Object value) throws JSONException {
if (value == null || value.equals(null)) { if (value == null || value.equals(null)) {
@ -339,7 +139,7 @@ public class JSONWriter {
if (value instanceof Number) { if (value instanceof Number) {
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
final String numberAsString = JSONObject.numberToString((Number) value); final String numberAsString = JSONObject.numberToString((Number) value);
if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) { if (JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) {
// Close enough to a JSON number that we will return it unquoted // Close enough to a JSON number that we will return it unquoted
return numberAsString; return numberAsString;
} }
@ -362,15 +162,217 @@ public class JSONWriter {
if (value.getClass().isArray()) { if (value.getClass().isArray()) {
return new JSONArray(value).toString(); return new JSONArray(value).toString();
} }
if(value instanceof Enum<?>){ if (value instanceof Enum<?>) {
return JSONObject.quote(((Enum<?>)value).name()); return JSONObject.quote(((Enum<?>) value).name());
} }
return JSONObject.quote(value.toString()); return JSONObject.quote(value.toString());
} }
/**
* 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) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
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 m Mode
* @param c Closing character
* @return this
* @throws JSONException If unbalanced.
*/
private JSONWriter end(char m, char c) throws JSONException {
if (this.mode != m) {
throw new JSONException(m == 'a'
? "Misplaced endArray."
: "Misplaced endObject.");
}
this.pop(m);
try {
this.writer.append(c);
} catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
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 {
JSONObject topObject = this.stack[this.top - 1];
// don't use the built in putOnce method to maintain Android support
if (topObject.has(string)) {
throw new JSONException("Duplicate key \"" + string + "\"");
}
topObject.put(string, 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) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
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 * Append either the value <code>true</code> or the value
* <code>false</code>. * <code>false</code>.
*
* @param b A boolean. * @param b A boolean.
* @return this * @return this
* @throws JSONException * @throws JSONException
@ -381,6 +383,7 @@ public class JSONWriter {
/** /**
* Append a double value. * Append a double value.
*
* @param d A double. * @param d A double.
* @return this * @return this
* @throws JSONException If the number is not finite. * @throws JSONException If the number is not finite.
@ -391,6 +394,7 @@ public class JSONWriter {
/** /**
* Append a long value. * Append a long value.
*
* @param l A long. * @param l A long.
* @return this * @return this
* @throws JSONException * @throws JSONException
@ -402,8 +406,9 @@ public class JSONWriter {
/** /**
* Append an object value. * Append an object value.
*
* @param object The object to append. It can be null, or a Boolean, Number, * @param object The object to append. It can be null, or a Boolean, Number,
* String, JSONObject, or JSONArray, or an object that implements JSONString. * String, JSONObject, or JSONArray, or an object that implements JSONString.
* @return this * @return this
* @throws JSONException If the value is out of sequence. * @throws JSONException If the value is out of sequence.
*/ */

View File

@ -29,12 +29,14 @@ import java.util.Properties;
/** /**
* Converts a Property file data into JSONObject and back. * Converts a Property file data into JSONObject and back.
*
* @author JSON.org * @author JSON.org
* @version 2015-05-05 * @version 2015-05-05
*/ */
public class Property { public class Property {
/** /**
* Converts a property file object into a JSONObject. The property file object is a table of name value pairs. * Converts a property file object into a JSONObject. The property file object is a table of name value pairs.
*
* @param properties java.util.Properties * @param properties java.util.Properties
* @return JSONObject * @return JSONObject
* @throws JSONException * @throws JSONException
@ -45,8 +47,8 @@ public class Property {
JSONObject jo = new JSONObject(); JSONObject jo = new JSONObject();
if (properties != null && !properties.isEmpty()) { if (properties != null && !properties.isEmpty()) {
Enumeration<?> enumProperties = properties.propertyNames(); Enumeration<?> enumProperties = properties.propertyNames();
while(enumProperties.hasMoreElements()) { while (enumProperties.hasMoreElements()) {
String name = (String)enumProperties.nextElement(); String name = (String) enumProperties.nextElement();
jo.put(name, properties.getProperty(name)); jo.put(name, properties.getProperty(name));
} }
} }
@ -55,14 +57,15 @@ public class Property {
/** /**
* Converts the JSONObject into a property file object. * Converts the JSONObject into a property file object.
*
* @param jo JSONObject * @param jo JSONObject
* @return java.util.Properties * @return java.util.Properties
* @throws JSONException * @throws JSONException
*/ */
public static Properties toProperties(JSONObject jo) throws JSONException { public static Properties toProperties(JSONObject jo) throws JSONException {
Properties properties = new Properties(); Properties properties = new Properties();
if (jo != null) { if (jo != null) {
// Don't use the new entrySet API to maintain Android support // Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) { for (final String key : jo.keySet()) {
Object value = jo.opt(key); Object value = jo.opt(key);
if (!JSONObject.NULL.equals(value)) { if (!JSONObject.NULL.equals(value)) {

View File

@ -38,31 +38,49 @@ import java.util.Iterator;
@SuppressWarnings("boxing") @SuppressWarnings("boxing")
public class XML { public class XML {
/** The Character '&amp;'. */ /**
* The Character '&amp;'.
*/
public static final Character AMP = '&'; public static final Character AMP = '&';
/** The Character '''. */ /**
* The Character '''.
*/
public static final Character APOS = '\''; public static final Character APOS = '\'';
/** The Character '!'. */ /**
* The Character '!'.
*/
public static final Character BANG = '!'; public static final Character BANG = '!';
/** The Character '='. */ /**
* The Character '='.
*/
public static final Character EQ = '='; public static final Character EQ = '=';
/** The Character '>'. */ /**
* The Character '>'.
*/
public static final Character GT = '>'; public static final Character GT = '>';
/** The Character '&lt;'. */ /**
* The Character '&lt;'.
*/
public static final Character LT = '<'; public static final Character LT = '<';
/** The Character '?'. */ /**
* The Character '?'.
*/
public static final Character QUEST = '?'; public static final Character QUEST = '?';
/** The Character '"'. */ /**
* The Character '"'.
*/
public static final Character QUOT = '"'; public static final Character QUOT = '"';
/** The Character '/'. */ /**
* The Character '/'.
*/
public static final Character SLASH = '/'; public static final Character SLASH = '/';
/** /**
@ -79,7 +97,7 @@ public class XML {
* which is available in Java8 and above. * which is available in Java8 and above.
* *
* @see <a href= * @see <a href=
* "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a> * "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a>
*/ */
private static Iterable<Integer> codePointIterator(final String string) { private static Iterable<Integer> codePointIterator(final String string) {
return new Iterable<Integer>() { return new Iterable<Integer>() {
@ -121,37 +139,36 @@ public class XML {
* &apos; <small>(single quote / apostrophe)</small> is replaced by &amp;apos; * &apos; <small>(single quote / apostrophe)</small> is replaced by &amp;apos;
* </pre> * </pre>
* *
* @param string * @param string The string to be escaped.
* The string to be escaped.
* @return The escaped string. * @return The escaped string.
*/ */
public static String escape(String string) { public static String escape(String string) {
StringBuilder sb = new StringBuilder(string.length()); StringBuilder sb = new StringBuilder(string.length());
for (final int cp : codePointIterator(string)) { for (final int cp : codePointIterator(string)) {
switch (cp) { switch (cp) {
case '&': case '&':
sb.append("&amp;"); sb.append("&amp;");
break; break;
case '<': case '<':
sb.append("&lt;"); sb.append("&lt;");
break; break;
case '>': case '>':
sb.append("&gt;"); sb.append("&gt;");
break; break;
case '"': case '"':
sb.append("&quot;"); sb.append("&quot;");
break; break;
case '\'': case '\'':
sb.append("&apos;"); sb.append("&apos;");
break; break;
default: default:
if (mustEscape(cp)) { if (mustEscape(cp)) {
sb.append("&#x"); sb.append("&#x");
sb.append(Integer.toHexString(cp)); sb.append(Integer.toHexString(cp));
sb.append(';'); sb.append(';');
} else { } else {
sb.appendCodePoint(cp); sb.appendCodePoint(cp);
} }
} }
} }
return sb.toString(); return sb.toString();
@ -174,20 +191,19 @@ public class XML {
&& cp != 0x9 && cp != 0x9
&& cp != 0xA && cp != 0xA
&& cp != 0xD && cp != 0xD
) || !( ) || !(
// valid the range of acceptable characters that aren't control // valid the range of acceptable characters that aren't control
(cp >= 0x20 && cp <= 0xD7FF) (cp >= 0x20 && cp <= 0xD7FF)
|| (cp >= 0xE000 && cp <= 0xFFFD) || (cp >= 0xE000 && cp <= 0xFFFD)
|| (cp >= 0x10000 && cp <= 0x10FFFF) || (cp >= 0x10000 && cp <= 0x10FFFF)
) )
; ;
} }
/** /**
* Removes XML escapes from the string. * Removes XML escapes from the string.
* *
* @param string * @param string string to remove escapes from
* string to remove escapes from
* @return string with converted entities * @return string with converted entities
*/ */
public static String unescape(String string) { public static String unescape(String string) {
@ -218,8 +234,7 @@ public class XML {
* Throw an exception if the string contains whitespace. Whitespace is not * Throw an exception if the string contains whitespace. Whitespace is not
* allowed in tagNames and attributes. * allowed in tagNames and attributes.
* *
* @param string * @param string A string.
* A string.
* @throws JSONException Thrown if the string contains whitespace or is empty. * @throws JSONException Thrown if the string contains whitespace or is empty.
*/ */
public static void noSpace(String string) throws JSONException { public static void noSpace(String string) throws JSONException {
@ -238,12 +253,9 @@ public class XML {
/** /**
* Scan the content following the named tag, attaching it to the context. * Scan the content following the named tag, attaching it to the context.
* *
* @param x * @param x The XMLTokener containing the source string.
* The XMLTokener containing the source string. * @param context The JSONObject that will include the new material.
* @param context * @param name The tag name.
* The JSONObject that will include the new material.
* @param name
* The tag name.
* @return true if the close tag is processed. * @return true if the close tag is processed.
* @throws JSONException * @throws JSONException
*/ */
@ -334,7 +346,7 @@ public class XML {
token = null; token = null;
jsonobject = new JSONObject(); jsonobject = new JSONObject();
boolean nilAttributeFound = false; boolean nilAttributeFound = false;
for (;;) { for (; ; ) {
if (token == null) { if (token == null) {
token = x.nextToken(); token = x.nextToken();
} }
@ -380,7 +392,7 @@ public class XML {
} else if (token == GT) { } else if (token == GT) {
// Content, between <...> and </...> // Content, between <...> and </...>
for (;;) { for (; ; ) {
token = x.nextContent(); token = x.nextContent();
if (token == null) { if (token == null) {
if (tagName != null) { if (tagName != null) {
@ -481,8 +493,7 @@ public class XML {
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> * "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored. * are ignored.
* *
* @param string * @param string The source string.
* The source string.
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string * @throws JSONException Thrown if there is an errors while parsing the string
*/ */
@ -519,18 +530,18 @@ public class XML {
* elements are represented as JSONArrays. Content text may be placed in a * elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> * "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored. * are ignored.
* * <p>
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to * 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. * numbers but will instead be the exact value as seen in the XML document.
* *
* @param reader The XML source reader. * @param reader The XML source reader.
* @param keepStrings If true, then values will not be coerced into boolean * @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings * or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string * @throws JSONException Thrown if there is an errors while parsing the string
*/ */
public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException { public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException {
if(keepStrings) { if (keepStrings) {
return toJSONObject(reader, XMLParserConfiguration.KEEP_STRINGS); return toJSONObject(reader, XMLParserConfiguration.KEEP_STRINGS);
} }
return toJSONObject(reader, XMLParserConfiguration.ORIGINAL); return toJSONObject(reader, XMLParserConfiguration.ORIGINAL);
@ -546,7 +557,7 @@ public class XML {
* elements are represented as JSONArrays. Content text may be placed in a * elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> * "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored. * are ignored.
* * <p>
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to * 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. * numbers but will instead be the exact value as seen in the XML document.
* *
@ -560,7 +571,7 @@ public class XML {
XMLTokener x = new XMLTokener(reader); XMLTokener x = new XMLTokener(reader);
while (x.more()) { while (x.more()) {
x.skipPast("<"); x.skipPast("<");
if(x.more()) { if (x.more()) {
parse(x, jo, null, config); parse(x, jo, null, config);
} }
} }
@ -577,14 +588,13 @@ public class XML {
* elements are represented as JSONArrays. Content text may be placed in a * elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> * "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored. * are ignored.
* * <p>
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to * 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. * numbers but will instead be the exact value as seen in the XML document.
* *
* @param string * @param string The source string.
* The source string.
* @param keepStrings If true, then values will not be coerced into boolean * @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings * or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string * @throws JSONException Thrown if there is an errors while parsing the string
*/ */
@ -602,12 +612,11 @@ public class XML {
* elements are represented as JSONArrays. Content text may be placed in a * elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> * "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored. * are ignored.
* * <p>
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to * 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. * numbers but will instead be the exact value as seen in the XML document.
* *
* @param string * @param string The source string.
* The source string.
* @param config Configuration options for the parser. * @param config Configuration options for the parser.
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string * @throws JSONException Thrown if there is an errors while parsing the string
@ -619,8 +628,7 @@ public class XML {
/** /**
* Convert a JSONObject into a well-formed, element-normal XML string. * Convert a JSONObject into a well-formed, element-normal XML string.
* *
* @param object * @param object A JSONObject.
* A JSONObject.
* @return A string. * @return A string.
* @throws JSONException Thrown if there is an error parsing the string * @throws JSONException Thrown if there is an error parsing the string
*/ */
@ -631,10 +639,8 @@ public class XML {
/** /**
* Convert a JSONObject into a well-formed, element-normal XML string. * Convert a JSONObject into a well-formed, element-normal XML string.
* *
* @param object * @param object A JSONObject.
* A JSONObject. * @param tagName The optional name of the enclosing tag.
* @param tagName
* The optional name of the enclosing tag.
* @return A string. * @return A string.
* @throws JSONException Thrown if there is an error parsing the string * @throws JSONException Thrown if there is an error parsing the string
*/ */
@ -645,12 +651,9 @@ public class XML {
/** /**
* Convert a JSONObject into a well-formed, element-normal XML string. * Convert a JSONObject into a well-formed, element-normal XML string.
* *
* @param object * @param object A JSONObject.
* A JSONObject. * @param tagName The optional name of the enclosing tag.
* @param tagName * @param config Configuration that can control output to XML.
* The optional name of the enclosing tag.
* @param config
* Configuration that can control output to XML.
* @return A string. * @return A string.
* @throws JSONException Thrown if there is an error parsing the string * @throws JSONException Thrown if there is an error parsing the string
*/ */
@ -687,7 +690,7 @@ public class XML {
ja = (JSONArray) value; ja = (JSONArray) value;
int jaLength = ja.length(); int jaLength = ja.length();
// don't use the new iterator API to maintain support for Android // don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) { for (int i = 0; i < jaLength; i++) {
if (i > 0) { if (i > 0) {
sb.append('\n'); sb.append('\n');
} }
@ -704,7 +707,7 @@ public class XML {
ja = (JSONArray) value; ja = (JSONArray) value;
int jaLength = ja.length(); int jaLength = ja.length();
// don't use the new iterator API to maintain support for Android // don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) { for (int i = 0; i < jaLength; i++) {
Object val = ja.opt(i); Object val = ja.opt(i);
if (val instanceof JSONArray) { if (val instanceof JSONArray) {
sb.append('<'); sb.append('<');
@ -740,15 +743,15 @@ public class XML {
} }
if (object != null && (object instanceof JSONArray || object.getClass().isArray())) { if (object != null && (object instanceof JSONArray || object.getClass().isArray())) {
if(object.getClass().isArray()) { if (object.getClass().isArray()) {
ja = new JSONArray(object); ja = new JSONArray(object);
} else { } else {
ja = (JSONArray) object; ja = (JSONArray) object;
} }
int jaLength = ja.length(); int jaLength = ja.length();
// don't use the new iterator API to maintain support for Android // don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) { for (int i = 0; i < jaLength; i++) {
Object val = ja.opt(i); Object val = ja.opt(i);
// XML does not have good support for arrays. If an array // XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an // appears in a place where XML is lacking, synthesize an
@ -761,7 +764,7 @@ public class XML {
string = (object == null) ? "null" : escape(object.toString()); string = (object == null) ? "null" : escape(object.toString());
return (tagName == null) ? "\"" + string + "\"" return (tagName == null) ? "\"" + string + "\""
: (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName
+ ">" + string + "</" + tagName + ">"; + ">" + string + "</" + tagName + ">";
} }
} }

View File

@ -25,13 +25,17 @@ SOFTWARE.
/** /**
* Configuration object for the XML parser. * Configuration object for the XML parser.
* @author AylwardJ
* *
* @author AylwardJ
*/ */
public class XMLParserConfiguration { public class XMLParserConfiguration {
/** Original Configuration of the XML Parser. */ /**
* Original Configuration of the XML Parser.
*/
public static final XMLParserConfiguration ORIGINAL = new XMLParserConfiguration(); public static final XMLParserConfiguration ORIGINAL = new XMLParserConfiguration();
/** Original configuration of the XML Parser except that values are kept as strings. */ /**
* Original configuration of the XML Parser except that values are kept as strings.
*/
public static final XMLParserConfiguration KEEP_STRINGS = new XMLParserConfiguration(true); public static final XMLParserConfiguration KEEP_STRINGS = new XMLParserConfiguration(true);
/** /**
* When parsing the XML into JSON, specifies if values should be kept as strings (true), or if * When parsing the XML into JSON, specifies if values should be kept as strings (true), or if
@ -53,16 +57,17 @@ public class XMLParserConfiguration {
/** /**
* Default parser configuration. Does not keep strings, and the CDATA Tag Name is "content". * Default parser configuration. Does not keep strings, and the CDATA Tag Name is "content".
*/ */
public XMLParserConfiguration () { public XMLParserConfiguration() {
this(false, "content", false); this(false, "content", false);
} }
/** /**
* Configure the parser string processing and use the default CDATA Tag Name as "content". * Configure the parser string processing and use the default CDATA Tag Name as "content".
*
* @param keepStrings <code>true</code> to parse all values as string. * @param keepStrings <code>true</code> to parse all values as string.
* <code>false</code> to try and convert XML string values into a JSON value. * <code>false</code> to try and convert XML string values into a JSON value.
*/ */
public XMLParserConfiguration (final boolean keepStrings) { public XMLParserConfiguration(final boolean keepStrings) {
this(keepStrings, "content", false); this(keepStrings, "content", false);
} }
@ -70,21 +75,23 @@ public class XMLParserConfiguration {
* Configure the parser string processing to try and convert XML values to JSON values and * Configure the parser string processing to try and convert XML values to JSON values and
* use the passed CDATA Tag Name the processing value. Pass <code>null</code> to * use the passed CDATA Tag Name the processing value. Pass <code>null</code> to
* disable CDATA processing * disable CDATA processing
*
* @param cDataTagName<code>null</code> to disable CDATA processing. Any other value * @param cDataTagName<code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA. * to use that value as the JSONObject key name to process as CDATA.
*/ */
public XMLParserConfiguration (final String cDataTagName) { public XMLParserConfiguration(final String cDataTagName) {
this(false, cDataTagName, false); this(false, cDataTagName, false);
} }
/** /**
* Configure the parser to use custom settings. * Configure the parser to use custom settings.
* @param keepStrings <code>true</code> to parse all values as string. *
* <code>false</code> to try and convert XML string values into a JSON value. * @param keepStrings <code>true</code> to parse all values as string.
* <code>false</code> to try and convert XML string values into a JSON value.
* @param cDataTagName<code>null</code> to disable CDATA processing. Any other value * @param cDataTagName<code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA. * to use that value as the JSONObject key name to process as CDATA.
*/ */
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) { public XMLParserConfiguration(final boolean keepStrings, final String cDataTagName) {
this.keepStrings = keepStrings; this.keepStrings = keepStrings;
this.cDataTagName = cDataTagName; this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = false; this.convertNilAttributeToNull = false;
@ -92,14 +99,15 @@ public class XMLParserConfiguration {
/** /**
* Configure the parser to use custom settings. * Configure the parser to use custom settings.
* @param keepStrings <code>true</code> to parse all values as string. *
* <code>false</code> to try and convert XML string values into a JSON value. * @param keepStrings <code>true</code> to parse all values as string.
* @param cDataTagName <code>null</code> to disable CDATA processing. Any other value * <code>false</code> to try and convert XML string values into a JSON value.
* to use that value as the JSONObject key name to process as CDATA. * @param cDataTagName <code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA.
* @param convertNilAttributeToNull <code>true</code> to parse values with attribute xsi:nil="true" as null. * @param convertNilAttributeToNull <code>true</code> to parse values with attribute xsi:nil="true" as null.
* <code>false</code> to parse values with attribute xsi:nil="true" as {"xsi:nil":true}. * <code>false</code> to parse values with attribute xsi:nil="true" as {"xsi:nil":true}.
*/ */
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) { public XMLParserConfiguration(final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) {
this.keepStrings = keepStrings; this.keepStrings = keepStrings;
this.cDataTagName = cDataTagName; this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = convertNilAttributeToNull; this.convertNilAttributeToNull = convertNilAttributeToNull;

View File

@ -29,28 +29,31 @@ import java.io.Reader;
/** /**
* The XMLTokener extends the JSONTokener to provide additional methods * The XMLTokener extends the JSONTokener to provide additional methods
* for the parsing of XML texts. * for the parsing of XML texts.
*
* @author JSON.org * @author JSON.org
* @version 2015-12-09 * @version 2015-12-09
*/ */
public class XMLTokener extends JSONTokener { public class XMLTokener extends JSONTokener {
/** The table of entity values. It initially contains Character values for /**
* amp, apos, gt, lt, quot. * 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; */
public static final java.util.HashMap<String, Character> entity;
static { static {
entity = new java.util.HashMap<String, Character>(8); entity = new java.util.HashMap<String, Character>(8);
entity.put("amp", XML.AMP); entity.put("amp", XML.AMP);
entity.put("apos", XML.APOS); entity.put("apos", XML.APOS);
entity.put("gt", XML.GT); entity.put("gt", XML.GT);
entity.put("lt", XML.LT); entity.put("lt", XML.LT);
entity.put("quot", XML.QUOT); entity.put("quot", XML.QUOT);
} }
/** /**
* Construct an XMLTokener from a Reader. * Construct an XMLTokener from a Reader.
*
* @param r A source reader. * @param r A source reader.
*/ */
public XMLTokener(Reader r) { public XMLTokener(Reader r) {
@ -59,100 +62,16 @@ public class XMLTokener extends JSONTokener {
/** /**
* Construct an XMLTokener from a string. * Construct an XMLTokener from a string.
*
* @param s A source string. * @param s A source string.
*/ */
public XMLTokener(String s) { public XMLTokener(String s) {
super(s); super(s);
} }
/**
* Get the text in the CDATA block.
* @return The string up to the <code>]]&gt;</code>.
* @throws JSONException If the <code>]]&gt;</code> is not found.
*/
public String nextCDATA() throws JSONException {
char c;
int i;
StringBuilder sb = new StringBuilder();
while (more()) {
c = next();
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();
}
}
throw syntaxError("Unclosed CDATA");
}
/**
* 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 == 0) {
return sb.toString().trim();
}
if (c == '<') {
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>&amp; &apos; &gt; &lt; &quot;</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(@SuppressWarnings("unused") 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();
return unescapeEntity(string);
}
/** /**
* Unescapes an XML entity encoding; * Unescapes an XML entity encoding;
*
* @param e entity (only the actual entity value, not the preceding & or ending ; * @param e entity (only the actual entity value, not the preceding & or ending ;
* @return * @return
*/ */
@ -171,25 +90,111 @@ public class XMLTokener extends JSONTokener {
// decimal encoded unicode // decimal encoded unicode
cp = Integer.parseInt(e.substring(1)); cp = Integer.parseInt(e.substring(1));
} }
return new String(new int[] {cp},0,1); return new String(new int[]{cp}, 0, 1);
} }
Character knownEntity = entity.get(e); Character knownEntity = entity.get(e);
if(knownEntity==null) { if (knownEntity == null) {
// we don't know the entity so keep it encoded // we don't know the entity so keep it encoded
return '&' + e + ';'; return '&' + e + ';';
} }
return knownEntity.toString(); return knownEntity.toString();
} }
/**
* Get the text in the CDATA block.
*
* @return The string up to the <code>]]&gt;</code>.
* @throws JSONException If the <code>]]&gt;</code> is not found.
*/
public String nextCDATA() throws JSONException {
char c;
int i;
StringBuilder sb = new StringBuilder();
while (more()) {
c = next();
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();
}
}
throw syntaxError("Unclosed CDATA");
}
/**
* 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 == 0) {
return sb.toString().trim();
}
if (c == '<') {
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>&amp; &apos; &gt; &lt; &quot;</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(@SuppressWarnings("unused") 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();
return unescapeEntity(string);
}
/** /**
* Returns the next XML meta token. This is used for skipping over <!...> * Returns the next XML meta token. This is used for skipping over <!...>
* and <?...?> structures. * and <?...?> structures.
*
* @return Syntax characters (<code>< > / = ! ?</code>) are returned as * @return Syntax characters (<code>< > / = ! ?</code>) are returned as
* Character, and strings and names are returned as Boolean. We don't care * Character, and strings and names are returned as Boolean. We don't care
* what the values actually are. * what the values actually are.
* @throws JSONException If a string is not properly closed or if the XML * @throws JSONException If a string is not properly closed or if the XML
* is badly structured. * is badly structured.
*/ */
public Object nextMeta() throws JSONException { public Object nextMeta() throws JSONException {
char c; char c;
@ -198,52 +203,52 @@ public class XMLTokener extends JSONTokener {
c = next(); c = next();
} while (Character.isWhitespace(c)); } while (Character.isWhitespace(c));
switch (c) { switch (c) {
case 0: case 0:
throw syntaxError("Misshaped meta tag"); throw syntaxError("Misshaped meta tag");
case '<': case '<':
return XML.LT; return XML.LT;
case '>': case '>':
return XML.GT; return XML.GT;
case '/': case '/':
return XML.SLASH; return XML.SLASH;
case '=': case '=':
return XML.EQ; return XML.EQ;
case '!': case '!':
return XML.BANG; return XML.BANG;
case '?': case '?':
return XML.QUEST; return XML.QUEST;
case '"': case '"':
case '\'': case '\'':
q = c; q = c;
for (;;) { for (; ; ) {
c = next(); c = next();
if (c == 0) { if (c == 0) {
throw syntaxError("Unterminated string"); throw syntaxError("Unterminated string");
}
if (c == q) {
return Boolean.TRUE;
}
} }
if (c == q) { default:
return Boolean.TRUE; 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;
}
} }
}
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;
}
}
} }
} }
@ -253,6 +258,7 @@ public class XMLTokener extends JSONTokener {
* brackets. It may be one of these characters: <code>/ > = ! ?</code> or it * 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 * may be a string wrapped in single quotes or double quotes, or it may be a
* name. * name.
*
* @return a String or a Character. * @return a String or a Character.
* @throws JSONException If the XML is not well formed. * @throws JSONException If the XML is not well formed.
*/ */
@ -264,70 +270,70 @@ public class XMLTokener extends JSONTokener {
c = next(); c = next();
} while (Character.isWhitespace(c)); } while (Character.isWhitespace(c));
switch (c) { switch (c) {
case 0: case 0:
throw syntaxError("Misshaped element"); throw syntaxError("Misshaped element");
case '<': case '<':
throw syntaxError("Misplaced '<'"); throw syntaxError("Misplaced '<'");
case '>': case '>':
return XML.GT; return XML.GT;
case '/': case '/':
return XML.SLASH; return XML.SLASH;
case '=': case '=':
return XML.EQ; return XML.EQ;
case '!': case '!':
return XML.BANG; return XML.BANG;
case '?': case '?':
return XML.QUEST; return XML.QUEST;
// Quoted string // Quoted string
case '"': case '"':
case '\'': case '\'':
q = c; q = c;
sb = new StringBuilder(); sb = new StringBuilder();
for (;;) { for (; ; ) {
c = next(); c = next();
if (c == 0) { if (c == 0) {
throw syntaxError("Unterminated string"); throw syntaxError("Unterminated string");
}
if (c == q) {
return sb.toString();
}
if (c == '&') {
sb.append(nextEntity(c));
} else {
sb.append(c);
}
} }
if (c == q) { default:
return sb.toString();
}
if (c == '&') {
sb.append(nextEntity(c));
} else {
sb.append(c);
}
}
default:
// Name // Name
sb = new StringBuilder(); sb = new StringBuilder();
for (;;) { for (; ; ) {
sb.append(c); sb.append(c);
c = next(); c = next();
if (Character.isWhitespace(c)) { if (Character.isWhitespace(c)) {
return sb.toString(); 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");
}
} }
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");
}
}
} }
} }
@ -335,6 +341,7 @@ public class XMLTokener extends JSONTokener {
/** /**
* Skip characters until past the requested string. * 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. * 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. * @param to A string to skip past.
*/ */
// The Android implementation of JSONTokener has a public method of public void skipPast(String to) // The Android implementation of JSONTokener has a public method of public void skipPast(String to)
@ -364,7 +371,7 @@ public class XMLTokener extends JSONTokener {
/* We will loop, possibly for all of the remaining characters. */ /* We will loop, possibly for all of the remaining characters. */
for (;;) { for (; ; ) {
j = offset; j = offset;
b = true; b = true;

View File

@ -1,10 +1,10 @@
package ch.m4th1eu.richpresence; package ch.m4th1eu.richpresence;
import ch.m4th1eu.json.JSONArray;
import ch.m4th1eu.json.JSONObject; import ch.m4th1eu.json.JSONObject;
import ch.m4th1eu.richpresence.events.AdvancedStatusEvent; import ch.m4th1eu.richpresence.events.AdvancedStatusEvent;
import ch.m4th1eu.richpresence.events.EventPresence; import ch.m4th1eu.richpresence.events.EventPresence;
import ch.m4th1eu.richpresence.proxy.CommonProxy; import ch.m4th1eu.richpresence.proxy.CommonProxy;
import net.minecraft.client.Minecraft;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.Mod.EventHandler;
@ -29,8 +29,7 @@ public class Main {
/** /**
* Variables pour la config * Variables pour la config
*/ */
public static String applicationId, largeimage, largeimagetext, serveurIP; public static String applicationId, largeimage, largeimagetext;
public static boolean advancedstatus;
public static Logger logger; public static Logger logger;
@ -38,18 +37,17 @@ public class Main {
public Main() { public Main() {
if (advancedstatus) { MinecraftForge.EVENT_BUS.register(new AdvancedStatusEvent());
MinecraftForge.EVENT_BUS.register(new AdvancedStatusEvent());
}
} }
@EventHandler @EventHandler
public void preInit(FMLPreInitializationEvent event) { public void preInit(FMLPreInitializationEvent event) {
logger = event.getModLog(); logger = event.getModLog();
proxy.preInit(event.getSuggestedConfigurationFile()); proxy.preInit(event.getSuggestedConfigurationFile());
//Configuration
//Configuration
event.getModConfigurationDirectory().mkdir(); event.getModConfigurationDirectory().mkdir();
File config_file = new File(event.getModConfigurationDirectory(), "\\" + Main.MODID + ".json"); File config_file = new File(event.getModConfigurationDirectory(), "\\" + Main.MODID + ".json");
if (!config_file.exists()) { if (!config_file.exists()) {
@ -66,29 +64,40 @@ public class Main {
try { try {
PrintWriter writer = new PrintWriter(config_file, "UTF-8"); PrintWriter writer = new PrintWriter(config_file, "UTF-8");
writer.println("{\n" + writer.println("{\n" +
" \"application-settings\": [\n" + " \"_comment\": \"Variables disponibles :\",\n" +
" {\n" + " \"_comment2\": \"%player-name% - Nom du joueur.\",\n" +
" \"applicationID\": \"601875975533232158\",\n" + " \"_comment3\": \"%server-connected-player% - Nombre de joueur connecté au serveur.\",\n" +
" \"large-image-name\": \"discord_logo\",\n" + " \"_comment4\": \"%server-max-slot% - Nombre de slots du serveur\",\n" +
" \"large-image-text\": \"En train de tester ce mod !\"\n" + " \"server-ip\": \"mc.hypixel.net\",\n" +
" \"server-port\": \"25565\",\n" +
" \"application-settings\": {\n" +
" \"applicationID\": \"601875975533232158\",\n" +
" \"large-image-name\": \"discord_logo\",\n" +
" \"large-image-text\": \"En train de tester ce mod !\"\n" +
" },\n" +
" \"advanced-status-custom\": {\n" +
" \"onJoinServer\": {\n" +
" \"enable\": true,\n" +
" \"message\": \"En jeu.\"\n" +
" },\n" +
" \"onQuitServer\": {\n" +
" \"enable\": true,\n" +
" \"message\": \"Dans le menu principal.\"\n" +
" },\n" +
" \"inPauseMenu\": {\n" +
" \"enable\": true,\n" +
" \"message\": \"Dans le menu pause.\"\n" +
" },\n" +
" \"inMainMenu\": {\n" +
" \"enable\": true,\n" +
" \"message\": \"Dans le menu principal.\"\n" +
" },\n" +
" \"inInventory\": {\n" +
" \"enable\": false,\n" +
" \"message\": \"Dans l'inventaire.\"\n" +
" }\n" + " }\n" +
" ],\n" + " }\n" +
" \"advanced-status\": true,\n" + "}");
" \"advanced-status-custom\": [\n" +
" {\n" +
" \"onJoinServer\": {\n" +
" \"message\": \"En jeu.\"\n" +
" },\n" +
" \"onQuitServer\": {\n" +
" \"message\": \"Dans le menu principal.\"\n" +
" },\n" +
" \"inPauseMenu\": {\n" +
" \"message\": \"Dans le menu pause\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}\n" +
"\n");
writer.close(); writer.close();
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
@ -102,23 +111,24 @@ public class Main {
applicationId = config.getJSONObject("application-settings").getString("applicationID"); applicationId = config.getJSONObject("application-settings").getString("applicationID");
largeimage = config.getJSONObject("application-settings").getString("large-image-name"); largeimage = config.getJSONObject("application-settings").getString("large-image-name");
largeimagetext = config.getJSONObject("application-settings").getString("large-image-text"); largeimagetext = Utils.replaceArgsString(config.getJSONObject("application-settings").getString("large-image-text"));
advancedstatus = config.getBoolean("advanced-status");
} }
@EventHandler @EventHandler
public void init(FMLInitializationEvent event) { public void init(FMLInitializationEvent event) {
JSONObject config = new JSONObject(Utils.readFileToString(new File(Minecraft.getMinecraft().mcDataDir, "\\config\\" + Main.MODID + ".json")));
proxy.init(); proxy.init();
rpcClient = new EventPresence(); rpcClient = new EventPresence();
proxy.rpcinit();
if (advancedstatus) {
proxy.rpcupdate("Dans le menu.", null);
} else {
proxy.rpcupdate("", null);
proxy.rpcinit();
if (config.getJSONObject("advanced-status-custom").getJSONObject("inMainMenu").getBoolean("enable")) {
proxy.rpcupdate(config.getJSONObject("advanced-status-custom").getJSONObject("inMainMenu").getString("message"), null, false);
} else {
proxy.rpcupdate("", null, false);
} }
} }

View File

@ -1,8 +1,13 @@
package ch.m4th1eu.richpresence; package ch.m4th1eu.richpresence;
import java.io.BufferedReader; import ch.m4th1eu.json.JSONObject;
import java.io.File; import net.minecraft.client.Minecraft;
import java.io.FileReader; import net.minecraft.network.INetHandler;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
public class Utils { public class Utils {
@ -27,4 +32,91 @@ public class Utils {
return "ERROR"; return "ERROR";
} }
} }
/**
* @author Nathanael
*/
public static String readTextFromURL(String url) throws IOException {
URL urlObject;
URLConnection uc;
StringBuilder parsedContentFromUrl = new StringBuilder();
urlObject = new URL(url);
uc = urlObject.openConnection();
uc.connect();
uc = urlObject.openConnection();
uc.addRequestProperty("User-Agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
uc.getInputStream();
InputStream is = uc.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
int ch;
while ((ch = in.read()) != -1) {
parsedContentFromUrl.append((char) ch);
}
return parsedContentFromUrl.toString();
}
/**
* @author M4TH1EU_
*/
public static String replaceArgsString(String variable) {
File config_file = new File(Minecraft.getMinecraft().mcDataDir, "\\config\\" + Main.MODID + ".json");
JSONObject config = new JSONObject(Utils.readFileToString(config_file));
String serverip = config.getString("server-ip");
String serverport = config.getString("server-port");
try {
variable = variable.replaceAll("%player-name%", Minecraft.getMinecraft().getSession().getUsername());
variable = variable.replaceAll("%server-connected-player%", readTextFromURL("https://minecraft-api.com/api/ping/playeronline.php?ip=" + serverip + "&port=" + serverport));
variable = variable.replaceAll("%server-max-slot%", readTextFromURL("https://minecraft-api.com/api/ping/maxplayer.php?ip=" + serverip + "&port=" + serverport));
} catch (Exception e) {
}
return variable;
}
public static void updateStatus(int id) {
Thread t = new Thread(() -> {
JSONObject config = new JSONObject(Utils.readFileToString(new File(Minecraft.getMinecraft().mcDataDir, "\\config\\" + Main.MODID + ".json")));
JSONObject onQuitServer = config.getJSONObject("advanced-status-custom").getJSONObject("onQuitServer");
JSONObject onJoinServer = config.getJSONObject("advanced-status-custom").getJSONObject("onJoinServer");
JSONObject inPauseMenu = config.getJSONObject("advanced-status-custom").getJSONObject("inPauseMenu");
JSONObject inMainMenu = config.getJSONObject("advanced-status-custom").getJSONObject("inMainMenu");
JSONObject inInventory = config.getJSONObject("advanced-status-custom").getJSONObject("inInventory");
switch (id) {
case 0:
Main.proxy.rpcupdate(Utils.replaceArgsString(config.getJSONObject("advanced-status-custom").getJSONObject("inMainMenu").getString("message")), null, false);
break;
case 1:
Main.proxy.rpcupdate(Utils.replaceArgsString(onJoinServer.getString("message")), null, false);
break;
case 2:
Main.proxy.rpcupdate(Utils.replaceArgsString(onQuitServer.getString("message")), null, false);
break;
case 3:
Main.proxy.rpcupdate(Utils.replaceArgsString(inPauseMenu.getString("message")), null, false);
break;
case 4:
Main.proxy.rpcupdate(Utils.replaceArgsString(inMainMenu.getString("message")), null, false);
break;
case 5:
Main.proxy.rpcupdate(Utils.replaceArgsString(inInventory.getString("message")), null, false);
break;
case 6:
Main.proxy.rpcupdate(Utils.replaceArgsString(config.getJSONObject("advanced-status-custom").getJSONObject("onJoinServer").getString("message")), null, false);
break;
default:
break;
}
});
t.start();
}
} }

View File

@ -5,7 +5,9 @@ import ch.m4th1eu.richpresence.Main;
import ch.m4th1eu.richpresence.Utils; import ch.m4th1eu.richpresence.Utils;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiIngameMenu; import net.minecraft.client.gui.GuiIngameMenu;
import net.minecraft.server.MinecraftServer; import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@ -24,28 +26,52 @@ public class AdvancedStatusEvent {
JSONObject config = new JSONObject(Utils.readFileToString(config_file)); JSONObject config = new JSONObject(Utils.readFileToString(config_file));
@SubscribeEvent @SubscribeEvent
public void onServerJoin(FMLNetworkEvent.ClientConnectedToServerEvent event) { public void onJoinServer(FMLNetworkEvent.ClientConnectedToServerEvent event) {
if (Main.advancedstatus) { JSONObject onJoinServer = config.getJSONObject("advanced-status-custom").getJSONObject("onJoinServer");
Main.proxy.rpcupdate(config.getJSONArray("advanced-status-custom").getJSONObject(0).getString("message"), null);
if (onJoinServer.getBoolean("enable")) {
Utils.updateStatus(1);
} }
} }
@SubscribeEvent @SubscribeEvent
public void onQuitServer(FMLNetworkEvent.ClientDisconnectionFromServerEvent event) { public void onQuitServer(FMLNetworkEvent.ClientDisconnectionFromServerEvent event) {
if (Main.advancedstatus) { JSONObject onQuitServer = config.getJSONObject("advanced-status-custom").getJSONObject("onQuitServer");
Main.proxy.rpcupdate(config.getJSONArray("advanced-status-custom").getJSONObject(1).getString("message"), null); if (onQuitServer.getBoolean("enable")) {
Utils.updateStatus(1);
} }
} }
@SubscribeEvent @SubscribeEvent
public void onGuiOpen(GuiOpenEvent event) { public void onGuiOpen(GuiOpenEvent event) {
if (Main.advancedstatus) {
JSONObject inPauseMenu = config.getJSONObject("advanced-status-custom").getJSONObject("inPauseMenu");
JSONObject inMainMenu = config.getJSONObject("advanced-status-custom").getJSONObject("inMainMenu");
JSONObject inInventory = config.getJSONObject("advanced-status-custom").getJSONObject("inInventory");
if (inPauseMenu.getBoolean("enable")) {
if (event.getGui() instanceof GuiIngameMenu) { if (event.getGui() instanceof GuiIngameMenu) {
Main.proxy.rpcupdate(config.getJSONArray("advanced-status-custom").getJSONObject(2).getString("message"), null); Utils.updateStatus(3);
}
}
if (inMainMenu.getBoolean("enable")) {
if (event.getGui() instanceof GuiMainMenu) {
Utils.updateStatus(4);
}
}
if (inInventory.getBoolean("enable")) {
if (event.getGui() instanceof GuiInventory) {
Utils.updateStatus(5);
}
}
if (event.getGui() == null) {
if (config.getJSONObject("advanced-status-custom").getJSONObject("onJoinServer").getBoolean("enable")) {
Utils.updateStatus(6);
} }
} }
} }
} }

View File

@ -12,17 +12,13 @@ public class EventPresence {
private static Thread callbackRunner; private static Thread callbackRunner;
public synchronized static final void init() { public synchronized static void init() {
DiscordEventHandlers handlers = new DiscordEventHandlers(); DiscordEventHandlers handlers = new DiscordEventHandlers();
DiscordRPC.discordInitialize(Main.applicationId, handlers, true, null); DiscordRPC.discordInitialize(Main.applicationId, handlers, true, null);
if (EventPresence.callbackRunner == null) { if (EventPresence.callbackRunner == null) {
(EventPresence.callbackRunner = new Thread(() -> { (EventPresence.callbackRunner = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) { while (!Thread.currentThread().isInterrupted()) {
DiscordRPC.discordRunCallbacks(); DiscordRPC.discordRunCallbacks();
try {
Thread.sleep(100L);
} catch (InterruptedException ex) {
}
} }
return; return;
}, "RPC-Callback-Handler")).start(); }, "RPC-Callback-Handler")).start();
@ -30,14 +26,16 @@ public class EventPresence {
Main.logger.info("EventPresence has been started."); Main.logger.info("EventPresence has been started.");
} }
public static final void updatePresence(String details, String action) { public synchronized static void updatePresence(String details, String action, Boolean changeTime) {
DiscordRichPresence presence = new DiscordRichPresence(); DiscordRichPresence presence = new DiscordRichPresence();
presence.largeImageKey = Main.largeimage; presence.largeImageKey = Main.largeimage;
presence.largeImageText = Main.largeimagetext; presence.largeImageText = Main.largeimagetext;
if (details != null) { if (details != null) {
presence.details = details; presence.details = details;
presence.startTimestamp = System.currentTimeMillis() / 1000L; if (changeTime) {
presence.startTimestamp = System.currentTimeMillis() / 1000L;
}
} else if (action != null) { } else if (action != null) {
presence.state = action; presence.state = action;
} }

View File

@ -28,7 +28,7 @@ public class ClientProxy extends CommonProxy {
} }
@Override @Override
public void rpcupdate(String details, String action) { public void rpcupdate(String details, String action, Boolean changeTime) {
EventPresence.updatePresence(details, action); EventPresence.updatePresence(details, action, changeTime);
} }
} }

View File

@ -19,7 +19,7 @@ public class CommonProxy {
public void rpcinit() { public void rpcinit() {
} }
public void rpcupdate(String details, String action) { public void rpcupdate(String details, String action, Boolean changeTime) {
} }
} }