parent
03b91a04c7
commit
c9b0cbc5e8
@ -0,0 +1,284 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
/** |
||||
* This provides static methods to convert comma delimited text into a |
||||
* JSONArray, and to convert a JSONArray into comma delimited text. Comma |
||||
* delimited text is a very popular format for data interchange. It is |
||||
* understood by most database, spreadsheet, and organizer programs. |
||||
* <p> |
||||
* Each row of text represents a row in a table or a data record. Each row |
||||
* ends with a NEWLINE character. Each row contains one or more values. |
||||
* Values are separated by commas. A value can contain any character except |
||||
* for comma, unless is is wrapped in single quotes or double quotes. |
||||
* <p> |
||||
* The first row usually contains the names of the columns. |
||||
* <p> |
||||
* A comma delimited list can be converted into a JSONArray of JSONObjects. |
||||
* The names for the elements in the JSONObjects can be taken from the names |
||||
* in the first row. |
||||
* @author JSON.org |
||||
* @version 2016-05-01 |
||||
*/ |
||||
public class CDL { |
||||
|
||||
/** |
||||
* Get the next value. The value can be wrapped in quotes. The value can |
||||
* be empty. |
||||
* @param x A JSONTokener of the source text. |
||||
* @return The value string, or null if empty. |
||||
* @throws JSONException if the quoted string is badly formed. |
||||
*/ |
||||
private static String getValue(JSONTokener x) throws JSONException { |
||||
char c; |
||||
char q; |
||||
StringBuffer sb; |
||||
do { |
||||
c = x.next(); |
||||
} while (c == ' ' || c == '\t'); |
||||
switch (c) { |
||||
case 0: |
||||
return null; |
||||
case '"': |
||||
case '\'': |
||||
q = c; |
||||
sb = new StringBuffer(); |
||||
for (;;) { |
||||
c = x.next(); |
||||
if (c == q) { |
||||
//Handle escaped double-quote
|
||||
if(x.next() != '\"') |
||||
{ |
||||
x.back(); |
||||
break; |
||||
} |
||||
} |
||||
if (c == 0 || c == '\n' || c == '\r') { |
||||
throw x.syntaxError("Missing close quote '" + q + "'."); |
||||
} |
||||
sb.append(c); |
||||
} |
||||
return sb.toString(); |
||||
case ',': |
||||
x.back(); |
||||
return ""; |
||||
default: |
||||
x.back(); |
||||
return x.nextTo(','); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Produce a JSONArray of strings from a row of comma delimited values. |
||||
* @param x A JSONTokener of the source text. |
||||
* @return A JSONArray of strings. |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { |
||||
JSONArray ja = new JSONArray(); |
||||
for (;;) { |
||||
String value = getValue(x); |
||||
char c = x.next(); |
||||
if (value == null || |
||||
(ja.length() == 0 && value.length() == 0 && c != ',')) { |
||||
return null; |
||||
} |
||||
ja.put(value); |
||||
for (;;) { |
||||
if (c == ',') { |
||||
break; |
||||
} |
||||
if (c != ' ') { |
||||
if (c == '\n' || c == '\r' || c == 0) { |
||||
return ja; |
||||
} |
||||
throw x.syntaxError("Bad character '" + c + "' (" + |
||||
(int)c + ")."); |
||||
} |
||||
c = x.next(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Produce a JSONObject from a row of comma delimited text, using a |
||||
* parallel JSONArray of strings to provides the names of the elements. |
||||
* @param names A JSONArray of names. This is commonly obtained from the |
||||
* first row of a comma delimited text file using the rowToJSONArray |
||||
* method. |
||||
* @param x A JSONTokener of the source text. |
||||
* @return A JSONObject combining the names and values. |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) |
||||
throws JSONException { |
||||
JSONArray ja = rowToJSONArray(x); |
||||
return ja != null ? ja.toJSONObject(names) : null; |
||||
} |
||||
|
||||
/** |
||||
* Produce a comma delimited text row from a JSONArray. Values containing |
||||
* the comma character will be quoted. Troublesome characters may be |
||||
* removed. |
||||
* @param ja A JSONArray of strings. |
||||
* @return A string ending in NEWLINE. |
||||
*/ |
||||
public static String rowToString(JSONArray ja) { |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (int i = 0; i < ja.length(); i += 1) { |
||||
if (i > 0) { |
||||
sb.append(','); |
||||
} |
||||
Object object = ja.opt(i); |
||||
if (object != null) { |
||||
String string = object.toString(); |
||||
if (string.length() > 0 && (string.indexOf(',') >= 0 || |
||||
string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 || |
||||
string.indexOf(0) >= 0 || string.charAt(0) == '"')) { |
||||
sb.append('"'); |
||||
int length = string.length(); |
||||
for (int j = 0; j < length; j += 1) { |
||||
char c = string.charAt(j); |
||||
if (c >= ' ' && c != '"') { |
||||
sb.append(c); |
||||
} |
||||
} |
||||
sb.append('"'); |
||||
} else { |
||||
sb.append(string); |
||||
} |
||||
} |
||||
} |
||||
sb.append('\n'); |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string, |
||||
* using the first row as a source of names. |
||||
* @param string The comma delimited text. |
||||
* @return A JSONArray of JSONObjects. |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONArray toJSONArray(String string) throws JSONException { |
||||
return toJSONArray(new JSONTokener(string)); |
||||
} |
||||
|
||||
/** |
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string, |
||||
* using the first row as a source of names. |
||||
* @param x The JSONTokener containing the comma delimited text. |
||||
* @return A JSONArray of JSONObjects. |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONArray toJSONArray(JSONTokener x) throws JSONException { |
||||
return toJSONArray(rowToJSONArray(x), x); |
||||
} |
||||
|
||||
/** |
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string |
||||
* using a supplied JSONArray as the source of element names. |
||||
* @param names A JSONArray of strings. |
||||
* @param string The comma delimited text. |
||||
* @return A JSONArray of JSONObjects. |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONArray toJSONArray(JSONArray names, String string) |
||||
throws JSONException { |
||||
return toJSONArray(names, new JSONTokener(string)); |
||||
} |
||||
|
||||
/** |
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string |
||||
* using a supplied JSONArray as the source of element names. |
||||
* @param names A JSONArray of strings. |
||||
* @param x A JSONTokener of the source text. |
||||
* @return A JSONArray of JSONObjects. |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x) |
||||
throws JSONException { |
||||
if (names == null || names.length() == 0) { |
||||
return null; |
||||
} |
||||
JSONArray ja = new JSONArray(); |
||||
for (;;) { |
||||
JSONObject jo = rowToJSONObject(names, x); |
||||
if (jo == null) { |
||||
break; |
||||
} |
||||
ja.put(jo); |
||||
} |
||||
if (ja.length() == 0) { |
||||
return null; |
||||
} |
||||
return ja; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Produce a comma delimited text from a JSONArray of JSONObjects. The |
||||
* first row will be a list of names obtained by inspecting the first |
||||
* JSONObject. |
||||
* @param ja A JSONArray of JSONObjects. |
||||
* @return A comma delimited text. |
||||
* @throws JSONException |
||||
*/ |
||||
public static String toString(JSONArray ja) throws JSONException { |
||||
JSONObject jo = ja.optJSONObject(0); |
||||
if (jo != null) { |
||||
JSONArray names = jo.names(); |
||||
if (names != null) { |
||||
return rowToString(names) + toString(names, ja); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Produce a comma delimited text from a JSONArray of JSONObjects using |
||||
* a provided list of names. The list of names is not included in the |
||||
* output. |
||||
* @param names A JSONArray of strings. |
||||
* @param ja A JSONArray of JSONObjects. |
||||
* @return A comma delimited text. |
||||
* @throws JSONException |
||||
*/ |
||||
public static String toString(JSONArray names, JSONArray ja) |
||||
throws JSONException { |
||||
if (names == null || names.length() == 0) { |
||||
return null; |
||||
} |
||||
StringBuffer sb = new StringBuffer(); |
||||
for (int i = 0; i < ja.length(); i += 1) { |
||||
JSONObject jo = ja.optJSONObject(i); |
||||
if (jo != null) { |
||||
sb.append(rowToString(jo.toJSONArray(names))); |
||||
} |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
} |
@ -0,0 +1,169 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
/** |
||||
* Convert a web browser cookie specification to a JSONObject and back. |
||||
* JSON and Cookies are both notations for name/value pairs. |
||||
* @author JSON.org |
||||
* @version 2015-12-09 |
||||
*/ |
||||
public class Cookie { |
||||
|
||||
/** |
||||
* Produce a copy of a string in which the characters '+', '%', '=', ';' |
||||
* and control characters are replaced with "%hh". This is a gentle form |
||||
* of URL encoding, attempting to cause as little distortion to the |
||||
* string as possible. The characters '=' and ';' are meta characters in |
||||
* cookies. By convention, they are escaped using the URL-encoding. This is |
||||
* only a convention, not a standard. Often, cookies are expected to have |
||||
* encoded values. We encode '=' and ';' because we must. We encode '%' and |
||||
* '+' because they are meta characters in URL encoding. |
||||
* @param string The source string. |
||||
* @return The escaped result. |
||||
*/ |
||||
public static String escape(String string) { |
||||
char c; |
||||
String s = string.trim(); |
||||
int length = s.length(); |
||||
StringBuilder sb = new StringBuilder(length); |
||||
for (int i = 0; i < length; i += 1) { |
||||
c = s.charAt(i); |
||||
if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { |
||||
sb.append('%'); |
||||
sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16)); |
||||
sb.append(Character.forDigit((char)(c & 0x0f), 16)); |
||||
} else { |
||||
sb.append(c); |
||||
} |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a cookie specification string into a JSONObject. The string |
||||
* will contain a name value pair separated by '='. The name and the value |
||||
* will be unescaped, possibly converting '+' and '%' sequences. The |
||||
* cookie properties may follow, separated by ';', also represented as |
||||
* name=value (except the secure property, which does not have a value). |
||||
* The name will be stored under the key "name", and the value will be |
||||
* stored under the key "value". This method does not do checking or |
||||
* validation of the parameters. It only converts the cookie string into |
||||
* a JSONObject. |
||||
* @param string The cookie specification string. |
||||
* @return A JSONObject containing "name", "value", and possibly other |
||||
* members. |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONObject toJSONObject(String string) throws JSONException { |
||||
String name; |
||||
JSONObject jo = new JSONObject(); |
||||
Object value; |
||||
JSONTokener x = new JSONTokener(string); |
||||
jo.put("name", x.nextTo('=')); |
||||
x.next('='); |
||||
jo.put("value", x.nextTo(';')); |
||||
x.next(); |
||||
while (x.more()) { |
||||
name = unescape(x.nextTo("=;")); |
||||
if (x.next() != '=') { |
||||
if (name.equals("secure")) { |
||||
value = Boolean.TRUE; |
||||
} else { |
||||
throw x.syntaxError("Missing '=' in cookie parameter."); |
||||
} |
||||
} else { |
||||
value = unescape(x.nextTo(';')); |
||||
x.next(); |
||||
} |
||||
jo.put(name, value); |
||||
} |
||||
return jo; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a JSONObject into a cookie specification string. The JSONObject |
||||
* must contain "name" and "value" members. |
||||
* If the JSONObject contains "expires", "domain", "path", or "secure" |
||||
* members, they will be appended to the cookie specification string. |
||||
* All other members are ignored. |
||||
* @param jo A JSONObject |
||||
* @return A cookie specification string |
||||
* @throws JSONException |
||||
*/ |
||||
public static String toString(JSONObject jo) throws JSONException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
|
||||
sb.append(escape(jo.getString("name"))); |
||||
sb.append("="); |
||||
sb.append(escape(jo.getString("value"))); |
||||
if (jo.has("expires")) { |
||||
sb.append(";expires="); |
||||
sb.append(jo.getString("expires")); |
||||
} |
||||
if (jo.has("domain")) { |
||||
sb.append(";domain="); |
||||
sb.append(escape(jo.getString("domain"))); |
||||
} |
||||
if (jo.has("path")) { |
||||
sb.append(";path="); |
||||
sb.append(escape(jo.getString("path"))); |
||||
} |
||||
if (jo.optBoolean("secure")) { |
||||
sb.append(";secure"); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Convert <code>%</code><i>hh</i> sequences to single characters, and |
||||
* convert plus to space. |
||||
* @param string A string that may contain |
||||
* <code>+</code> <small>(plus)</small> and |
||||
* <code>%</code><i>hh</i> sequences. |
||||
* @return The unescaped string. |
||||
*/ |
||||
public static String unescape(String string) { |
||||
int length = string.length(); |
||||
StringBuilder sb = new StringBuilder(length); |
||||
for (int i = 0; i < length; ++i) { |
||||
char c = string.charAt(i); |
||||
if (c == '+') { |
||||
c = ' '; |
||||
} else if (c == '%' && i + 2 < length) { |
||||
int d = JSONTokener.dehexchar(string.charAt(i + 1)); |
||||
int e = JSONTokener.dehexchar(string.charAt(i + 2)); |
||||
if (d >= 0 && e >= 0) { |
||||
c = (char)(d * 16 + e); |
||||
i += 2; |
||||
} |
||||
} |
||||
sb.append(c); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
} |
@ -0,0 +1,89 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* Convert a web browser cookie list string to a JSONObject and back. |
||||
* @author JSON.org |
||||
* @version 2015-12-09 |
||||
*/ |
||||
public class CookieList { |
||||
|
||||
/** |
||||
* Convert a cookie list into a JSONObject. A cookie list is a sequence |
||||
* of name/value pairs. The names are separated from the values by '='. |
||||
* The pairs are separated by ';'. The names and the values |
||||
* will be unescaped, possibly converting '+' and '%' sequences. |
||||
* |
||||
* To add a cookie to a cooklist, |
||||
* cookielistJSONObject.put(cookieJSONObject.getString("name"), |
||||
* cookieJSONObject.getString("value")); |
||||
* @param string A cookie list string |
||||
* @return A JSONObject |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONObject toJSONObject(String string) throws JSONException { |
||||
JSONObject jo = new JSONObject(); |
||||
JSONTokener x = new JSONTokener(string); |
||||
while (x.more()) { |
||||
String name = Cookie.unescape(x.nextTo('=')); |
||||
x.next('='); |
||||
jo.put(name, Cookie.unescape(x.nextTo(';'))); |
||||
x.next(); |
||||
} |
||||
return jo; |
||||
} |
||||
|
||||
/** |
||||
* Convert a JSONObject into a cookie list. A cookie list is a sequence |
||||
* of name/value pairs. The names are separated from the values by '='. |
||||
* The pairs are separated by ';'. The characters '%', '+', '=', and ';' |
||||
* in the names and values are replaced by "%hh". |
||||
* @param jo A JSONObject |
||||
* @return A cookie list string |
||||
* @throws JSONException |
||||
*/ |
||||
public static String toString(JSONObject jo) throws JSONException { |
||||
boolean b = false; |
||||
Iterator<String> keys = jo.keys(); |
||||
String string; |
||||
StringBuilder sb = new StringBuilder(); |
||||
while (keys.hasNext()) { |
||||
string = keys.next(); |
||||
if (!jo.isNull(string)) { |
||||
if (b) { |
||||
sb.append(';'); |
||||
} |
||||
sb.append(Cookie.escape(string)); |
||||
sb.append("="); |
||||
sb.append(Cookie.escape(jo.getString(string))); |
||||
b = true; |
||||
} |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
} |
@ -0,0 +1,164 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
import java.util.Iterator; |
||||
import java.util.Locale; |
||||
|
||||
/** |
||||
* Convert an HTTP header to a JSONObject and back. |
||||
* @author JSON.org |
||||
* @version 2015-12-09 |
||||
*/ |
||||
public class HTTP { |
||||
|
||||
/** Carriage return/line feed. */ |
||||
public static final String CRLF = "\r\n"; |
||||
|
||||
/** |
||||
* Convert an HTTP header string into a JSONObject. It can be a request |
||||
* header or a response header. A request header will contain |
||||
* <pre>{ |
||||
* Method: "POST" (for example), |
||||
* "Request-URI": "/" (for example), |
||||
* "HTTP-Version": "HTTP/1.1" (for example) |
||||
* }</pre> |
||||
* A response header will contain |
||||
* <pre>{ |
||||
* "HTTP-Version": "HTTP/1.1" (for example), |
||||
* "Status-Code": "200" (for example), |
||||
* "Reason-Phrase": "OK" (for example) |
||||
* }</pre> |
||||
* In addition, the other parameters in the header will be captured, using |
||||
* the HTTP field names as JSON names, so that <pre> |
||||
* Date: Sun, 26 May 2002 18:06:04 GMT |
||||
* Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s |
||||
* Cache-Control: no-cache</pre> |
||||
* become |
||||
* <pre>{... |
||||
* Date: "Sun, 26 May 2002 18:06:04 GMT", |
||||
* Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s", |
||||
* "Cache-Control": "no-cache", |
||||
* ...}</pre> |
||||
* It does no further checking or conversion. It does not parse dates. |
||||
* It does not do '%' transforms on URLs. |
||||
* @param string An HTTP header string. |
||||
* @return A JSONObject containing the elements and attributes |
||||
* of the XML string. |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONObject toJSONObject(String string) throws JSONException { |
||||
JSONObject jo = new JSONObject(); |
||||
HTTPTokener x = new HTTPTokener(string); |
||||
String token; |
||||
|
||||
token = x.nextToken(); |
||||
if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { |
||||
|
||||
// Response
|
||||
|
||||
jo.put("HTTP-Version", token); |
||||
jo.put("Status-Code", x.nextToken()); |
||||
jo.put("Reason-Phrase", x.nextTo('\0')); |
||||
x.next(); |
||||
|
||||
} else { |
||||
|
||||
// Request
|
||||
|
||||
jo.put("Method", token); |
||||
jo.put("Request-URI", x.nextToken()); |
||||
jo.put("HTTP-Version", x.nextToken()); |
||||
} |
||||
|
||||
// Fields
|
||||
|
||||
while (x.more()) { |
||||
String name = x.nextTo(':'); |
||||
x.next(':'); |
||||
jo.put(name, x.nextTo('\0')); |
||||
x.next(); |
||||
} |
||||
return jo; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a JSONObject into an HTTP header. A request header must contain |
||||
* <pre>{ |
||||
* Method: "POST" (for example), |
||||
* "Request-URI": "/" (for example), |
||||
* "HTTP-Version": "HTTP/1.1" (for example) |
||||
* }</pre> |
||||
* A response header must contain |
||||
* <pre>{ |
||||
* "HTTP-Version": "HTTP/1.1" (for example), |
||||
* "Status-Code": "200" (for example), |
||||
* "Reason-Phrase": "OK" (for example) |
||||
* }</pre> |
||||
* Any other members of the JSONObject will be output as HTTP fields. |
||||
* The result will end with two CRLF pairs. |
||||
* @param jo A JSONObject |
||||
* @return An HTTP header string. |
||||
* @throws JSONException if the object does not contain enough |
||||
* information. |
||||
*/ |
||||
public static String toString(JSONObject jo) throws JSONException { |
||||
Iterator<String> keys = jo.keys(); |
||||
String string; |
||||
StringBuilder sb = new StringBuilder(); |
||||
if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { |
||||
sb.append(jo.getString("HTTP-Version")); |
||||
sb.append(' '); |
||||
sb.append(jo.getString("Status-Code")); |
||||
sb.append(' '); |
||||
sb.append(jo.getString("Reason-Phrase")); |
||||
} else if (jo.has("Method") && jo.has("Request-URI")) { |
||||
sb.append(jo.getString("Method")); |
||||
sb.append(' '); |
||||
sb.append('"'); |
||||
sb.append(jo.getString("Request-URI")); |
||||
sb.append('"'); |
||||
sb.append(' '); |
||||
sb.append(jo.getString("HTTP-Version")); |
||||
} else { |
||||
throw new JSONException("Not enough material for an HTTP header."); |
||||
} |
||||
sb.append(CRLF); |
||||
while (keys.hasNext()) { |
||||
string = keys.next(); |
||||
if (!"HTTP-Version".equals(string) && !"Status-Code".equals(string) && |
||||
!"Reason-Phrase".equals(string) && !"Method".equals(string) && |
||||
!"Request-URI".equals(string) && !jo.isNull(string)) { |
||||
sb.append(string); |
||||
sb.append(": "); |
||||
sb.append(jo.getString(string)); |
||||
sb.append(CRLF); |
||||
} |
||||
} |
||||
sb.append(CRLF); |
||||
return sb.toString(); |
||||
} |
||||
} |
@ -0,0 +1,77 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
/** |
||||
* The HTTPTokener extends the JSONTokener to provide additional methods |
||||
* for the parsing of HTTP headers. |
||||
* @author JSON.org |
||||
* @version 2015-12-09 |
||||
*/ |
||||
public class HTTPTokener extends JSONTokener { |
||||
|
||||
/** |
||||
* Construct an HTTPTokener from a string. |
||||
* @param string A source string. |
||||
*/ |
||||
public HTTPTokener(String string) { |
||||
super(string); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the next token or string. This is used in parsing HTTP headers. |
||||
* @throws JSONException |
||||
* @return A String. |
||||
*/ |
||||
public String nextToken() throws JSONException { |
||||
char c; |
||||
char q; |
||||
StringBuilder sb = new StringBuilder(); |
||||
do { |
||||
c = next(); |
||||
} while (Character.isWhitespace(c)); |
||||
if (c == '"' || c == '\'') { |
||||
q = c; |
||||
for (;;) { |
||||
c = next(); |
||||
if (c < ' ') { |
||||
throw syntaxError("Unterminated string."); |
||||
} |
||||
if (c == q) { |
||||
return sb.toString(); |
||||
} |
||||
sb.append(c); |
||||
} |
||||
} |
||||
for (;;) { |
||||
if (c == 0 || Character.isWhitespace(c)) { |
||||
return sb.toString(); |
||||
} |
||||
sb.append(c); |
||||
c = next(); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@ |
||||
package org.json; |
||||
|
||||
/** |
||||
* The JSONException is thrown by the JSON.org classes when things are amiss. |
||||
* |
||||
* @author JSON.org |
||||
* @version 2015-12-09 |
||||
*/ |
||||
public class JSONException extends RuntimeException { |
||||
/** Serialization ID */ |
||||
private static final long serialVersionUID = 0; |
||||
|
||||
/** |
||||
* Constructs a JSONException with an explanatory message. |
||||
* |
||||
* @param message |
||||
* Detail about the reason for the exception. |
||||
*/ |
||||
public JSONException(final String message) { |
||||
super(message); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a JSONException with an explanatory message and cause. |
||||
* |
||||
* @param message |
||||
* Detail about the reason for the exception. |
||||
* @param cause |
||||
* The cause. |
||||
*/ |
||||
public JSONException(final String message, final Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new JSONException with the specified cause. |
||||
* |
||||
* @param cause |
||||
* The cause. |
||||
*/ |
||||
public JSONException(final Throwable cause) { |
||||
super(cause.getMessage(), cause); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,552 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2008 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
|
||||
/** |
||||
* This provides static methods to convert an XML text into a JSONArray or |
||||
* JSONObject, and to covert a JSONArray or JSONObject into an XML text using |
||||
* the JsonML transform. |
||||
* |
||||
* @author JSON.org |
||||
* @version 2016-01-30 |
||||
*/ |
||||
public class JSONML { |
||||
/** |
||||
* Parse XML values and store them in a JSONArray. |
||||
* @param x The XMLTokener containing the source string. |
||||
* @param arrayForm true if array form, false if object form. |
||||
* @param ja The JSONArray that is containing the current tag or null |
||||
* if we are at the outermost level. |
||||
* @param keepStrings Don't type-convert text nodes and attibute values |
||||
* @return A JSONArray if the value is the outermost tag, otherwise null. |
||||
* @throws JSONException |
||||
*/ |
||||
private static Object parse( |
||||
XMLTokener x, |
||||
boolean arrayForm, |
||||
JSONArray ja, |
||||
boolean keepStrings |
||||
) throws JSONException { |
||||
String attribute; |
||||
char c; |
||||
String closeTag = null; |
||||
int i; |
||||
JSONArray newja = null; |
||||
JSONObject newjo = null; |
||||
Object token; |
||||
String tagName = null; |
||||
|
||||
// Test for and skip past these forms:
|
||||
// <!-- ... -->
|
||||
// <![ ... ]]>
|
||||
// <! ... >
|
||||
// <? ... ?>
|
||||
|
||||
while (true) { |
||||
if (!x.more()) { |
||||
throw x.syntaxError("Bad XML"); |
||||
} |
||||
token = x.nextContent(); |
||||
if (token == XML.LT) { |
||||
token = x.nextToken(); |
||||
if (token instanceof Character) { |
||||
if (token == XML.SLASH) { |
||||
|
||||
// Close tag </
|
||||
|
||||
token = x.nextToken(); |
||||
if (!(token instanceof String)) { |
||||
throw new JSONException( |
||||
"Expected a closing name instead of '" + |
||||
token + "'."); |
||||
} |
||||
if (x.nextToken() != XML.GT) { |
||||
throw x.syntaxError("Misshaped close tag"); |
||||
} |
||||
return token; |
||||
} else if (token == XML.BANG) { |
||||
|
||||
// <!
|
||||
|
||||
c = x.next(); |
||||
if (c == '-') { |
||||
if (x.next() == '-') { |
||||
x.skipPast("-->"); |
||||
} else { |
||||
x.back(); |
||||
} |
||||
} else if (c == '[') { |
||||
token = x.nextToken(); |
||||
if (token.equals("CDATA") && x.next() == '[') { |
||||
if (ja != null) { |
||||
ja.put(x.nextCDATA()); |
||||
} |
||||
} else { |
||||
throw x.syntaxError("Expected 'CDATA['"); |
||||
} |
||||
} else { |
||||
i = 1; |
||||
do { |
||||
token = x.nextMeta(); |
||||
if (token == null) { |
||||
throw x.syntaxError("Missing '>' after '<!'."); |
||||
} else if (token == XML.LT) { |
||||
i += 1; |
||||
} else if (token == XML.GT) { |
||||
i -= 1; |
||||
} |
||||
} while (i > 0); |
||||
} |
||||
} else if (token == XML.QUEST) { |
||||
|
||||
// <?
|
||||
|
||||
x.skipPast("?>"); |
||||
} else { |
||||
throw x.syntaxError("Misshaped tag"); |
||||
} |
||||
|
||||
// Open tag <
|
||||
|
||||
} else { |
||||
if (!(token instanceof String)) { |
||||
throw x.syntaxError("Bad tagName '" + token + "'."); |
||||
} |
||||
tagName = (String)token; |
||||
newja = new JSONArray(); |
||||
newjo = new JSONObject(); |
||||
if (arrayForm) { |
||||
newja.put(tagName); |
||||
if (ja != null) { |
||||
ja.put(newja); |
||||
} |
||||
} else { |
||||
newjo.put("tagName", tagName); |
||||
if (ja != null) { |
||||
ja.put(newjo); |
||||
} |
||||
} |
||||
token = null; |
||||
for (;;) { |
||||
if (token == null) { |
||||
token = x.nextToken(); |
||||
} |
||||
if (token == null) { |
||||
throw x.syntaxError("Misshaped tag"); |
||||
} |
||||
if (!(token instanceof String)) { |
||||
break; |
||||
} |
||||
|
||||
// attribute = value
|
||||
|
||||
attribute = (String)token; |
||||
if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { |
||||
throw x.syntaxError("Reserved attribute."); |
||||
} |
||||
token = x.nextToken(); |
||||
if (token == XML.EQ) { |
||||
token = x.nextToken(); |
||||
if (!(token instanceof String)) { |
||||
throw x.syntaxError("Missing value"); |
||||
} |
||||
newjo.accumulate(attribute, keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token)); |
||||
token = null; |
||||
} else { |
||||
newjo.accumulate(attribute, ""); |
||||
} |
||||
} |
||||
if (arrayForm && newjo.length() > 0) { |
||||
newja.put(newjo); |
||||
} |
||||
|
||||
// Empty tag <.../>
|
||||
|
||||
if (token == XML.SLASH) { |
||||
if (x.nextToken() != XML.GT) { |
||||
throw x.syntaxError("Misshaped tag"); |
||||
} |
||||
if (ja == null) { |
||||
if (arrayForm) { |
||||
return newja; |
||||
} |
||||
return newjo; |
||||
} |
||||
|
||||
// Content, between <...> and </...>
|
||||
|
||||
} else { |
||||
if (token != XML.GT) { |
||||
throw x.syntaxError("Misshaped tag"); |
||||
} |
||||
closeTag = (String)parse(x, arrayForm, newja, keepStrings); |
||||
if (closeTag != null) { |
||||
if (!closeTag.equals(tagName)) { |
||||
throw x.syntaxError("Mismatched '" + tagName + |
||||
"' and '" + closeTag + "'"); |
||||
} |
||||
tagName = null; |
||||
if (!arrayForm && newja.length() > 0) { |
||||
newjo.put("childNodes", newja); |
||||
} |
||||
if (ja == null) { |
||||
if (arrayForm) { |
||||
return newja; |
||||
} |
||||
return newjo; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
if (ja != null) { |
||||
ja.put(token instanceof String |
||||
? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token) |
||||
: token); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONArray using the JsonML transform. Each XML tag is represented as |
||||
* a JSONArray in which the first element is the tag name. If the tag has |
||||
* attributes, then the second element will be JSONObject containing the |
||||
* name/value pairs. If the tag contains children, then strings and |
||||
* JSONArrays will represent the child tags. |
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||
* @param string The source string. |
||||
* @return A JSONArray containing the structured data from the XML string. |
||||
* @throws JSONException Thrown on error converting to a JSONArray |
||||
*/ |
||||
public static JSONArray toJSONArray(String string) throws JSONException { |
||||
return (JSONArray)parse(new XMLTokener(string), true, null, false); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONArray using the JsonML transform. Each XML tag is represented as |
||||
* a JSONArray in which the first element is the tag name. If the tag has |
||||
* attributes, then the second element will be JSONObject containing the |
||||
* name/value pairs. If the tag contains children, then strings and |
||||
* JSONArrays will represent the child tags. |
||||
* As opposed to toJSONArray this method does not attempt to convert |
||||
* any text node or attribute value to any type |
||||
* but just leaves it as a string. |
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||
* @param string The source string. |
||||
* @param keepStrings If true, then values will not be coerced into boolean |
||||
* or numeric values and will instead be left as strings |
||||
* @return A JSONArray containing the structured data from the XML string. |
||||
* @throws JSONException Thrown on error converting to a JSONArray |
||||
*/ |
||||
public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { |
||||
return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONArray using the JsonML transform. Each XML tag is represented as |
||||
* a JSONArray in which the first element is the tag name. If the tag has |
||||
* attributes, then the second element will be JSONObject containing the |
||||
* name/value pairs. If the tag contains children, then strings and |
||||
* JSONArrays will represent the child content and tags. |
||||
* As opposed to toJSONArray this method does not attempt to convert |
||||
* any text node or attribute value to any type |
||||
* but just leaves it as a string. |
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||
* @param x An XMLTokener. |
||||
* @param keepStrings If true, then values will not be coerced into boolean |
||||
* or numeric values and will instead be left as strings |
||||
* @return A JSONArray containing the structured data from the XML string. |
||||
* @throws JSONException Thrown on error converting to a JSONArray |
||||
*/ |
||||
public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { |
||||
return (JSONArray)parse(x, true, null, keepStrings); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONArray using the JsonML transform. Each XML tag is represented as |
||||
* a JSONArray in which the first element is the tag name. If the tag has |
||||
* attributes, then the second element will be JSONObject containing the |
||||
* name/value pairs. If the tag contains children, then strings and |
||||
* JSONArrays will represent the child content and tags. |
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||
* @param x An XMLTokener. |
||||
* @return A JSONArray containing the structured data from the XML string. |
||||
* @throws JSONException Thrown on error converting to a JSONArray |
||||
*/ |
||||
public static JSONArray toJSONArray(XMLTokener x) throws JSONException { |
||||
return (JSONArray)parse(x, true, null, false); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONObject using the JsonML transform. Each XML tag is represented as |
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then |
||||
* the attributes will be in the JSONObject as properties. If the tag |
||||
* contains children, the object will have a "childNodes" property which |
||||
* will be an array of strings and JsonML JSONObjects. |
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||
* @param string The XML source text. |
||||
* @return A JSONObject containing the structured data from the XML string. |
||||
* @throws JSONException Thrown on error converting to a JSONObject |
||||
*/ |
||||
public static JSONObject toJSONObject(String string) throws JSONException { |
||||
return (JSONObject)parse(new XMLTokener(string), false, null, false); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONObject using the JsonML transform. Each XML tag is represented as |
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then |
||||
* the attributes will be in the JSONObject as properties. If the tag |
||||
* contains children, the object will have a "childNodes" property which |
||||
* will be an array of strings and JsonML JSONObjects. |
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||
* @param string The XML source text. |
||||
* @param keepStrings If true, then values will not be coerced into boolean |
||||
* or numeric values and will instead be left as strings |
||||
* @return A JSONObject containing the structured data from the XML string. |
||||
* @throws JSONException Thrown on error converting to a JSONObject |
||||
*/ |
||||
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { |
||||
return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONObject using the JsonML transform. Each XML tag is represented as |
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then |
||||
* the attributes will be in the JSONObject as properties. If the tag |
||||
* contains children, the object will have a "childNodes" property which |
||||
* will be an array of strings and JsonML JSONObjects. |
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||
* @param x An XMLTokener of the XML source text. |
||||
* @return A JSONObject containing the structured data from the XML string. |
||||
* @throws JSONException Thrown on error converting to a JSONObject |
||||
*/ |
||||
public static JSONObject toJSONObject(XMLTokener x) throws JSONException { |
||||
return (JSONObject)parse(x, false, null, false); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONObject using the JsonML transform. Each XML tag is represented as |
||||
* a JSONObject with a "tagName" property. If the tag has attributes, then |
||||
* the attributes will be in the JSONObject as properties. If the tag |
||||
* contains children, the object will have a "childNodes" property which |
||||
* will be an array of strings and JsonML JSONObjects. |
||||
|
||||
* Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored. |
||||
* @param x An XMLTokener of the XML source text. |
||||
* @param keepStrings If true, then values will not be coerced into boolean |
||||
* or numeric values and will instead be left as strings |
||||
* @return A JSONObject containing the structured data from the XML string. |
||||
* @throws JSONException Thrown on error converting to a JSONObject |
||||
*/ |
||||
public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { |
||||
return (JSONObject)parse(x, false, null, keepStrings); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Reverse the JSONML transformation, making an XML text from a JSONArray. |
||||
* @param ja A JSONArray. |
||||
* @return An XML string. |
||||
* @throws JSONException Thrown on error converting to a string |
||||
*/ |
||||
public static String toString(JSONArray ja) throws JSONException { |
||||
int i; |
||||
JSONObject jo; |
||||
String key; |
||||
Iterator<String> keys; |
||||
int length; |
||||
Object object; |
||||
StringBuilder sb = new StringBuilder(); |
||||
String tagName; |
||||
String value; |
||||
|
||||
// Emit <tagName
|
||||
|
||||
tagName = ja.getString(0); |
||||
XML.noSpace(tagName); |
||||
tagName = XML.escape(tagName); |
||||
sb.append('<'); |
||||
sb.append(tagName); |
||||
|
||||
object = ja.opt(1); |
||||
if (object instanceof JSONObject) { |
||||
i = 2; |
||||
jo = (JSONObject)object; |
||||
|
||||
// Emit the attributes
|
||||
|
||||
keys = jo.keys(); |
||||
while (keys.hasNext()) { |
||||
key = keys.next(); |
||||
XML.noSpace(key); |
||||
value = jo.optString(key); |
||||
if (value != null) { |
||||
sb.append(' '); |
||||
sb.append(XML.escape(key)); |
||||
sb.append('='); |
||||
sb.append('"'); |
||||
sb.append(XML.escape(value)); |
||||
sb.append('"'); |
||||
} |
||||
} |
||||
} else { |
||||
i = 1; |
||||
} |
||||
|
||||
// Emit content in body
|
||||
|
||||
length = ja.length(); |
||||
if (i >= length) { |
||||
sb.append('/'); |
||||
sb.append('>'); |
||||
} else { |
||||
sb.append('>'); |
||||
do { |
||||
object = ja.get(i); |
||||
i += 1; |
||||
if (object != null) { |
||||
if (object instanceof String) { |
||||
sb.append(XML.escape(object.toString())); |
||||
} else if (object instanceof JSONObject) { |
||||
sb.append(toString((JSONObject)object)); |
||||
} else if (object instanceof JSONArray) { |
||||
sb.append(toString((JSONArray)object)); |
||||
} else { |
||||
sb.append(object.toString()); |
||||
} |
||||
} |
||||
} while (i < length); |
||||
sb.append('<'); |
||||
sb.append('/'); |
||||
sb.append(tagName); |
||||
sb.append('>'); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Reverse the JSONML transformation, making an XML text from a JSONObject. |
||||
* The JSONObject must contain a "tagName" property. If it has children, |
||||
* then it must have a "childNodes" property containing an array of objects. |
||||
* The other properties are attributes with string values. |
||||
* @param jo A JSONObject. |
||||
* @return An XML string. |
||||
* @throws JSONException Thrown on error converting to a string |
||||
*/ |
||||
public static String toString(JSONObject jo) throws JSONException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
int i; |
||||
JSONArray ja; |
||||
String key; |
||||
Iterator<String> keys; |
||||
int length; |
||||
Object object; |
||||
String tagName; |
||||
String value; |
||||
|
||||
//Emit <tagName
|
||||
|
||||
tagName = jo.optString("tagName"); |
||||
if (tagName == null) { |
||||
return XML.escape(jo.toString()); |
||||
} |
||||
XML.noSpace(tagName); |
||||
tagName = XML.escape(tagName); |
||||
sb.append('<'); |
||||
sb.append(tagName); |
||||
|
||||
//Emit the attributes
|
||||
|
||||
keys = jo.keys(); |
||||
while (keys.hasNext()) { |
||||
key = keys.next(); |
||||
if (!"tagName".equals(key) && !"childNodes".equals(key)) { |
||||
XML.noSpace(key); |
||||
value = jo.optString(key); |
||||
if (value != null) { |
||||
sb.append(' '); |
||||
sb.append(XML.escape(key)); |
||||
sb.append('='); |
||||
sb.append('"'); |
||||
sb.append(XML.escape(value)); |
||||
sb.append('"'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
//Emit content in body
|
||||
|
||||
ja = jo.optJSONArray("childNodes"); |
||||
if (ja == null) { |
||||
sb.append('/'); |
||||
sb.append('>'); |
||||
} else { |
||||
sb.append('>'); |
||||
length = ja.length(); |
||||
for (i = 0; i < length; i += 1) { |
||||
object = ja.get(i); |
||||
if (object != null) { |
||||
if (object instanceof String) { |
||||
sb.append(XML.escape(object.toString())); |
||||
} else if (object instanceof JSONObject) { |
||||
sb.append(toString((JSONObject)object)); |
||||
} else if (object instanceof JSONArray) { |
||||
sb.append(toString((JSONArray)object)); |
||||
} else { |
||||
sb.append(object.toString()); |
||||
} |
||||
} |
||||
} |
||||
sb.append('<'); |
||||
sb.append('/'); |
||||
sb.append(tagName); |
||||
sb.append('>'); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,267 @@ |
||||
package org.json; |
||||
|
||||
import static java.lang.String.format; |
||||
|
||||
import java.io.UnsupportedEncodingException; |
||||
import java.net.URLDecoder; |
||||
import java.net.URLEncoder; |
||||
import java.util.*; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
/** |
||||
* A JSON Pointer is a simple query language defined for JSON documents by |
||||
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>. |
||||
* |
||||
* In a nutshell, JSONPointer allows the user to navigate into a JSON document |
||||
* using strings, and retrieve targeted objects, like a simple form of XPATH. |
||||
* Path segments are separated by the '/' char, which signifies the root of |
||||
* the document when it appears as the first char of the string. Array |
||||
* elements are navigated using ordinals, counting from 0. JSONPointer strings |
||||
* may be extended to any arbitrary number of segments. If the navigation |
||||
* is successful, the matched item is returned. A matched item may be a |
||||
* JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building |
||||
* fails, an appropriate exception is thrown. If the navigation fails to find |
||||
* a match, a JSONPointerException is thrown. |
||||
* |
||||
* @author JSON.org |
||||
* @version 2016-05-14 |
||||
*/ |
||||
public class JSONPointer { |
||||
|
||||
// used for URL encoding and decoding
|
||||
private static final String ENCODING = "utf-8"; |
||||
|
||||
/** |
||||
* This class allows the user to build a JSONPointer in steps, using |
||||
* exactly one segment in each step. |
||||
*/ |
||||
public static class Builder { |
||||
|
||||
// Segments for the eventual JSONPointer string
|
||||
private final List<String> refTokens = new ArrayList<String>(); |
||||
|
||||
/** |
||||
* Creates a {@code JSONPointer} instance using the tokens previously set using the |
||||
* {@link #append(String)} method calls. |
||||
*/ |
||||
public JSONPointer build() { |
||||
return new JSONPointer(refTokens); |
||||
} |
||||
|
||||
/** |
||||
* Adds an arbitary token to the list of reference tokens. It can be any non-null value. |
||||
* |
||||
* Unlike in the case of JSON string or URI fragment representation of JSON pointers, the |
||||
* argument of this method MUST NOT be escaped. If you want to query the property called |
||||
* {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no |
||||
* need to escape it as {@code "a~0b"}. |
||||
* |
||||
* @param token the new token to be appended to the list |
||||
* @return {@code this} |
||||
* @throws NullPointerException if {@code token} is null |
||||
*/ |
||||
public Builder append(String token) { |
||||
if (token == null) { |
||||
throw new NullPointerException("token cannot be null"); |
||||
} |
||||
refTokens.add(token); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Adds an integer to the reference token list. Although not necessarily, mostly this token will |
||||
* denote an array index. |
||||
* |
||||
* @param arrayIndex the array index to be added to the token list |
||||
* @return {@code this} |
||||
*/ |
||||
public Builder append(int arrayIndex) { |
||||
refTokens.add(String.valueOf(arrayIndex)); |
||||
return this; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Static factory method for {@link Builder}. Example usage: |
||||
* |
||||
* <pre><code> |
||||
* JSONPointer pointer = JSONPointer.builder() |
||||
* .append("obj") |
||||
* .append("other~key").append("another/key") |
||||
* .append("\"") |
||||
* .append(0) |
||||
* .build(); |
||||
* </code></pre> |
||||
* |
||||
* @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained |
||||
* {@link Builder#append(String)} calls. |
||||
*/ |
||||
public static Builder builder() { |
||||
return new Builder(); |
||||
} |
||||
|
||||
// Segments for the JSONPointer string
|
||||
private final List<String> refTokens; |
||||
|
||||
/** |
||||
* Pre-parses and initializes a new {@code JSONPointer} instance. If you want to |
||||
* evaluate the same JSON Pointer on different JSON documents then it is recommended |
||||
* to keep the {@code JSONPointer} instances due to performance considerations. |
||||
* |
||||
* @param pointer the JSON String or URI Fragment representation of the JSON pointer. |
||||
* @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer |
||||
*/ |
||||
public JSONPointer(String pointer) { |
||||
if (pointer == null) { |
||||
throw new NullPointerException("pointer cannot be null"); |
||||
} |
||||
if (pointer.isEmpty() || pointer.equals("#")) { |
||||
refTokens = Collections.emptyList(); |
||||
return; |
||||
} |
||||
if (pointer.startsWith("#/")) { |
||||
pointer = pointer.substring(2); |
||||
try { |
||||
pointer = URLDecoder.decode(pointer, ENCODING); |
||||
} catch (UnsupportedEncodingException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} else if (pointer.startsWith("/")) { |
||||
pointer = pointer.substring(1); |
||||
} else { |
||||
throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'"); |
||||
} |
||||
refTokens = new ArrayList<String>(); |
||||
for (String token : pointer.split("/")) { |
||||
refTokens.add(unescape(token)); |
||||
} |
||||
} |
||||
|
||||
public JSONPointer(List<String> refTokens) { |
||||
this.refTokens = new ArrayList<String>(refTokens); |
||||
} |
||||
|
||||
private String unescape(String token) { |
||||
return token.replace("~1", "/").replace("~0", "~") |
||||
.replace("\\\"", "\"") |
||||
.replace("\\\\", "\\"); |
||||
} |
||||
|
||||
/** |
||||
* Evaluates this JSON Pointer on the given {@code document}. The {@code document} |
||||
* is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty |
||||
* JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the |
||||
* returned value will be {@code document} itself. |
||||
* |
||||
* @param document the JSON document which should be the subject of querying. |
||||
* @return the result of the evaluation |
||||
* @throws JSONPointerException if an error occurs during evaluation |
||||
*/ |
||||
public Object queryFrom(Object document) { |
||||
if (refTokens.isEmpty()) { |
||||
return document; |
||||
} |
||||
Object current = document; |
||||
for (String token : refTokens) { |
||||
if (current instanceof JSONObject) { |
||||
current = ((JSONObject) current).opt(unescape(token)); |
||||
} else if (current instanceof JSONArray) { |
||||
current = readByIndexToken(current, token); |
||||
} else { |
||||
throw new JSONPointerException(format( |
||||
"value [%s] is not an array or object therefore its key %s cannot be resolved", current, |
||||
token)); |
||||
} |
||||
} |
||||
return current; |
||||
} |
||||
|
||||
/** |
||||
* Matches a JSONArray element by ordinal position |
||||
* @param current the JSONArray to be evaluated |
||||
* @param indexToken the array index in string form |
||||
* @return the matched object. If no matching item is found a |
||||
* JSONPointerException is thrown |
||||
*/ |
||||
private Object readByIndexToken(Object current, String indexToken) { |
||||
try { |
||||
int index = Integer.parseInt(indexToken); |
||||
JSONArray currentArr = (JSONArray) current; |
||||
if (index >= currentArr.length()) { |
||||
throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index, |
||||
currentArr.length())); |
||||
} |
||||
return currentArr.get(index); |
||||
} catch (NumberFormatException e) { |
||||
throw new JSONPointerException(format("%s is not an array index", indexToken), e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a string representing the JSONPointer path value using string |
||||
* representation |
||||
*/ |
||||
@Override |
||||
public String toString() { |
||||
StringBuilder rval = new StringBuilder(""); |
||||
for (String token: refTokens) { |
||||
rval.append('/').append(escape(token)); |
||||
} |
||||
return rval.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Escapes path segment values to an unambiguous form. |
||||
* The escape char to be inserted is '~'. The chars to be escaped |
||||
* are ~, which maps to ~0, and /, which maps to ~1. Backslashes |
||||
* and double quote chars are also escaped. |
||||
* @param token the JSONPointer segment value to be escaped |
||||
* @return the escaped value for the token |
||||
*/ |
||||
private String escape(String token) { |
||||
return token.replace("~", "~0") |
||||
.replace("/", "~1") |
||||
.replace("\\", "\\\\") |
||||
.replace("\"", "\\\""); |
||||
} |
||||
|
||||
/** |
||||
* Returns a string representing the JSONPointer path value using URI |
||||
* fragment identifier representation |
||||
*/ |
||||
public String toURIFragment() { |
||||
try { |
||||
StringBuilder rval = new StringBuilder("#"); |
||||
for (String token : refTokens) { |
||||
rval.append('/').append(URLEncoder.encode(token, ENCODING)); |
||||
} |
||||
return rval.toString(); |
||||
} catch (UnsupportedEncodingException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,45 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
/** |
||||
* The JSONPointerException is thrown by {@link JSONPointer} if an error occurs |
||||
* during evaluating a pointer. |
||||
* |
||||
* @author JSON.org |
||||
* @version 2016-05-13 |
||||
*/ |
||||
public class JSONPointerException extends JSONException { |
||||
private static final long serialVersionUID = 8872944667561856751L; |
||||
|
||||
public JSONPointerException(String message) { |
||||
super(message); |
||||
} |
||||
|
||||
public JSONPointerException(String message, Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,18 @@ |
||||
package org.json; |
||||
/** |
||||
* The <code>JSONString</code> interface allows a <code>toJSONString()</code> |
||||
* method so that a class can change the behavior of |
||||
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>, |
||||
* and <code>JSONWriter.value(</code>Object<code>)</code>. The |
||||
* <code>toJSONString</code> method will be used instead of the default behavior |
||||
* of using the Object's <code>toString()</code> method and quoting the result. |
||||
*/ |
||||
public interface JSONString { |
||||
/** |
||||
* The <code>toJSONString</code> method allows a class to produce its own JSON |
||||
* serialization. |
||||
* |
||||
* @return A strictly syntactically correct JSON text. |
||||
*/ |
||||
public String toJSONString(); |
||||
} |
@ -0,0 +1,78 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2006 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
import java.io.StringWriter; |
||||
|
||||
/** |
||||
* JSONStringer provides a quick and convenient way of producing JSON text. |
||||
* The texts produced strictly conform to JSON syntax rules. No whitespace is |
||||
* added, so the results are ready for transmission or storage. Each instance of |
||||
* JSONStringer can produce one JSON text. |
||||
* <p> |
||||
* A JSONStringer instance provides a <code>value</code> method for appending |
||||
* values to the |
||||
* text, and a <code>key</code> |
||||
* method for adding keys before values in objects. There are <code>array</code> |
||||
* and <code>endArray</code> methods that make and bound array values, and |
||||
* <code>object</code> and <code>endObject</code> methods which make and bound |
||||
* object values. All of these methods return the JSONWriter instance, |
||||
* permitting cascade style. For example, <pre> |
||||
* myString = new JSONStringer() |
||||
* .object() |
||||
* .key("JSON") |
||||
* .value("Hello, World!") |
||||
* .endObject() |
||||
* .toString();</pre> which produces the string <pre> |
||||
* {"JSON":"Hello, World!"}</pre> |
||||
* <p> |
||||
* The first method called must be <code>array</code> or <code>object</code>. |
||||
* There are no methods for adding commas or colons. JSONStringer adds them for |
||||
* you. Objects and arrays can be nested up to 20 levels deep. |
||||
* <p> |
||||
* This can sometimes be easier than using a JSONObject to build a string. |
||||
* @author JSON.org |
||||
* @version 2015-12-09 |
||||
*/ |
||||
public class JSONStringer extends JSONWriter { |
||||
/** |
||||
* Make a fresh JSONStringer. It can be used to build one JSON text. |
||||
*/ |
||||
public JSONStringer() { |
||||
super(new StringWriter()); |
||||
} |
||||
|
||||
/** |
||||
* Return the JSON text. This method is used to obtain the product of the |
||||
* JSONStringer instance. It will return <code>null</code> if there was a |
||||
* problem in the construction of the JSON text (such as the calls to |
||||
* <code>array</code> were not properly balanced with calls to |
||||
* <code>endArray</code>). |
||||
* @return The JSON text. |
||||
*/ |
||||
public String toString() { |
||||
return this.mode == 'd' ? this.writer.toString() : null; |
||||
} |
||||
} |
@ -0,0 +1,475 @@ |
||||
package org.json; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.io.Reader; |
||||
import java.io.StringReader; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
/** |
||||
* A JSONTokener takes a source string and extracts characters and tokens from |
||||
* it. It is used by the JSONObject and JSONArray constructors to parse |
||||
* JSON source strings. |
||||
* @author JSON.org |
||||
* @version 2014-05-03 |
||||
*/ |
||||
public class JSONTokener { |
||||
|
||||
private long character; |
||||
private boolean eof; |
||||
private long index; |
||||
private long line; |
||||
private char previous; |
||||
private Reader reader; |
||||
private boolean usePrevious; |
||||
|
||||
|
||||
/** |
||||
* Construct a JSONTokener from a Reader. |
||||
* |
||||
* @param reader A reader. |
||||
*/ |
||||
public JSONTokener(Reader reader) { |
||||
this.reader = reader.markSupported() |
||||
? reader |
||||
: new BufferedReader(reader); |
||||
this.eof = false; |
||||
this.usePrevious = false; |
||||
this.previous = 0; |
||||
this.index = 0; |
||||
this.character = 1; |
||||
this.line = 1; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Construct a JSONTokener from an InputStream. |
||||
* @param inputStream The source. |
||||
*/ |
||||
public JSONTokener(InputStream inputStream) { |
||||
this(new InputStreamReader(inputStream)); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Construct a JSONTokener from a string. |
||||
* |
||||
* @param s A source string. |
||||
*/ |
||||
public JSONTokener(String s) { |
||||
this(new StringReader(s)); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Back up one character. This provides a sort of lookahead capability, |
||||
* so that you can test for a digit or letter before attempting to parse |
||||
* the next number or identifier. |
||||
* @throws JSONException Thrown if trying to step back more than 1 step |
||||
* or if already at the start of the string |
||||
*/ |
||||
public void back() throws JSONException { |
||||
if (this.usePrevious || this.index <= 0) { |
||||
throw new JSONException("Stepping back two steps is not supported"); |
||||
} |
||||
this.index -= 1; |
||||
this.character -= 1; |
||||
this.usePrevious = true; |
||||
this.eof = false; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the hex value of a character (base16). |
||||
* @param c A character between '0' and '9' or between 'A' and 'F' or |
||||
* between 'a' and 'f'. |
||||
* @return An int between 0 and 15, or -1 if c was not a hex digit. |
||||
*/ |
||||
public static int dehexchar(char c) { |
||||
if (c >= '0' && c <= '9') { |
||||
return c - '0'; |
||||
} |
||||
if (c >= 'A' && c <= 'F') { |
||||
return c - ('A' - 10); |
||||
} |
||||
if (c >= 'a' && c <= 'f') { |
||||
return c - ('a' - 10); |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
/** |
||||
* @return true if at the end of the file and we didn't step back |
||||
*/ |
||||
public boolean end() { |
||||
return this.eof && !this.usePrevious; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Determine if the source string still contains characters that next() |
||||
* can consume. |
||||
* @return true if not yet at the end of the source. |
||||
* @throws JSONException thrown if there is an error stepping forward |
||||
* or backward while checking for more data. |
||||
*/ |
||||
public boolean more() throws JSONException { |
||||
this.next(); |
||||
if (this.end()) { |
||||
return false; |
||||
} |
||||
this.back(); |
||||
return true; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the next character in the source string. |
||||
* |
||||
* @return The next character, or 0 if past the end of the source string. |
||||
* @throws JSONException Thrown if there is an error reading the source string. |
||||
*/ |
||||
public char next() throws JSONException { |
||||
int c; |
||||
if (this.usePrevious) { |
||||
this.usePrevious = false; |
||||
c = this.previous; |
||||
} else { |
||||
try { |
||||
c = this.reader.read(); |
||||
} catch (IOException exception) { |
||||
throw new JSONException(exception); |
||||
} |
||||
|
||||
if (c <= 0) { // End of stream
|
||||
this.eof = true; |
||||
c = 0; |
||||
} |
||||
} |
||||
this.index += 1; |
||||
if (this.previous == '\r') { |
||||
this.line += 1; |
||||
this.character = c == '\n' ? 0 : 1; |
||||
} else if (c == '\n') { |
||||
this.line += 1; |
||||
this.character = 0; |
||||
} else { |
||||
this.character += 1; |
||||
} |
||||
this.previous = (char) c; |
||||
return this.previous; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Consume the next character, and check that it matches a specified |
||||
* character. |
||||
* @param c The character to match. |
||||
* @return The character. |
||||
* @throws JSONException if the character does not match. |
||||
*/ |
||||
public char next(char c) throws JSONException { |
||||
char n = this.next(); |
||||
if (n != c) { |
||||
throw this.syntaxError("Expected '" + c + "' and instead saw '" + |
||||
n + "'"); |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the next n characters. |
||||
* |
||||
* @param n The number of characters to take. |
||||
* @return A string of n characters. |
||||
* @throws JSONException |
||||
* Substring bounds error if there are not |
||||
* n characters remaining in the source string. |
||||
*/ |
||||
public String next(int n) throws JSONException { |
||||
if (n == 0) { |
||||
return ""; |
||||
} |
||||
|
||||
char[] chars = new char[n]; |
||||
int pos = 0; |
||||
|
||||
while (pos < n) { |
||||
chars[pos] = this.next(); |
||||
if (this.end()) { |
||||
throw this.syntaxError("Substring bounds error"); |
||||
} |
||||
pos += 1; |
||||
} |
||||
return new String(chars); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the next char in the string, skipping whitespace. |
||||
* @throws JSONException Thrown if there is an error reading the source string. |
||||
* @return A character, or 0 if there are no more characters. |
||||
*/ |
||||
public char nextClean() throws JSONException { |
||||
for (;;) { |
||||
char c = this.next(); |
||||
if (c == 0 || c > ' ') { |
||||
return c; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Return the characters up to the next close quote character. |
||||
* Backslash processing is done. The formal JSON format does not |
||||
* allow strings in single quotes, but an implementation is allowed to |
||||
* accept them. |
||||
* @param quote The quoting character, either |
||||
* <code>"</code> <small>(double quote)</small> or |
||||
* <code>'</code> <small>(single quote)</small>. |
||||
* @return A String. |
||||
* @throws JSONException Unterminated string. |
||||
*/ |
||||
public String nextString(char quote) throws JSONException { |
||||
char c; |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (;;) { |
||||
c = this.next(); |
||||
switch (c) { |
||||
case 0: |
||||
case '\n': |
||||
case '\r': |
||||
throw this.syntaxError("Unterminated string"); |
||||
case '\\': |
||||
c = this.next(); |
||||
switch (c) { |
||||
case 'b': |
||||
sb.append('\b'); |
||||
break; |
||||
case 't': |
||||
sb.append('\t'); |
||||
break; |
||||
case 'n': |
||||
sb.append('\n'); |
||||
break; |
||||
case 'f': |
||||
sb.append('\f'); |
||||
break; |
||||
case 'r': |
||||
sb.append('\r'); |
||||
break; |
||||
case 'u': |
||||
try { |
||||
sb.append((char)Integer.parseInt(this.next(4), 16)); |
||||
} catch (NumberFormatException e) { |
||||
throw this.syntaxError("Illegal escape.", e); |
||||
} |
||||
break; |
||||
case '"': |
||||
case '\'': |
||||
case '\\': |
||||
case '/': |
||||
sb.append(c); |
||||
break; |
||||
default: |
||||
throw this.syntaxError("Illegal escape."); |
||||
} |
||||
break; |
||||
default: |
||||
if (c == quote) { |
||||
return sb.toString(); |
||||
} |
||||
sb.append(c); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the text up but not including the specified character or the |
||||
* end of line, whichever comes first. |
||||
* @param delimiter A delimiter character. |
||||
* @return A string. |
||||
* @throws JSONException Thrown if there is an error while searching |
||||
* for the delimiter |
||||
*/ |
||||
public String nextTo(char delimiter) throws JSONException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (;;) { |
||||
char c = this.next(); |
||||
if (c == delimiter || c == 0 || c == '\n' || c == '\r') { |
||||
if (c != 0) { |
||||
this.back(); |
||||
} |
||||
return sb.toString().trim(); |
||||
} |
||||
sb.append(c); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the text up but not including one of the specified delimiter |
||||
* characters or the end of line, whichever comes first. |
||||
* @param delimiters A set of delimiter characters. |
||||
* @return A string, trimmed. |
||||
* @throws JSONException Thrown if there is an error while searching |
||||
* for the delimiter |
||||
*/ |
||||
public String nextTo(String delimiters) throws JSONException { |
||||
char c; |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (;;) { |
||||
c = this.next(); |
||||
if (delimiters.indexOf(c) >= 0 || c == 0 || |
||||
c == '\n' || c == '\r') { |
||||
if (c != 0) { |
||||
this.back(); |
||||
} |
||||
return sb.toString().trim(); |
||||
} |
||||
sb.append(c); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the next value. The value can be a Boolean, Double, Integer, |
||||
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. |
||||
* @throws JSONException If syntax error. |
||||
* |
||||
* @return An object. |
||||
*/ |
||||
public Object nextValue() throws JSONException { |
||||
char c = this.nextClean(); |
||||
String string; |
||||
|
||||
switch (c) { |
||||
case '"': |
||||
case '\'': |
||||
return this.nextString(c); |
||||
case '{': |
||||
this.back(); |
||||
return new JSONObject(this); |
||||
case '[': |
||||
this.back(); |
||||
return new JSONArray(this); |
||||
} |
||||
|
||||
/* |
||||
* Handle unquoted text. This could be the values true, false, or |
||||
* null, or it can be a number. An implementation (such as this one) |
||||
* is allowed to also accept non-standard forms. |
||||
* |
||||
* Accumulate characters until we reach the end of the text or a |
||||
* formatting character. |
||||
*/ |
||||
|
||||
StringBuilder sb = new StringBuilder(); |
||||
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { |
||||
sb.append(c); |
||||
c = this.next(); |
||||
} |
||||
this.back(); |
||||
|
||||
string = sb.toString().trim(); |
||||
if ("".equals(string)) { |
||||
throw this.syntaxError("Missing value"); |
||||
} |
||||
return JSONObject.stringToValue(string); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Skip characters until the next character is the requested character. |
||||
* If the requested character is not found, no characters are skipped. |
||||
* @param to A character to skip to. |
||||
* @return The requested character, or zero if the requested character |
||||
* is not found. |
||||
* @throws JSONException Thrown if there is an error while searching |
||||
* for the to character |
||||
*/ |
||||
public char skipTo(char to) throws JSONException { |
||||
char c; |
||||
try { |
||||
long startIndex = this.index; |
||||
long startCharacter = this.character; |
||||
long startLine = this.line; |
||||
this.reader.mark(1000000); |
||||
do { |
||||
c = this.next(); |
||||
if (c == 0) { |
||||
this.reader.reset(); |
||||
this.index = startIndex; |
||||
this.character = startCharacter; |
||||
this.line = startLine; |
||||
return c; |
||||
} |
||||
} while (c != to); |
||||
} catch (IOException exception) { |
||||
throw new JSONException(exception); |
||||
} |
||||
this.back(); |
||||
return c; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Make a JSONException to signal a syntax error. |
||||
* |
||||
* @param message The error message. |
||||
* @return A JSONException object, suitable for throwing |
||||
*/ |
||||
public JSONException syntaxError(String message) { |
||||
return new JSONException(message + this.toString()); |
||||
} |
||||
|
||||
/** |
||||
* Make a JSONException to signal a syntax error. |
||||
* |
||||
* @param message The error message. |
||||
* @param causedBy The throwable that caused the error. |
||||
* @return A JSONException object, suitable for throwing |
||||
*/ |
||||
public JSONException syntaxError(String message, Throwable causedBy) { |
||||
return new JSONException(message + this.toString(), causedBy); |
||||
} |
||||
|
||||
/** |
||||
* Make a printable string of this JSONTokener. |
||||
* |
||||
* @return " at {index} [character {character} line {line}]" |
||||
*/ |
||||
@Override |
||||
public String toString() { |
||||
return " at " + this.index + " [character " + this.character + " line " + |
||||
this.line + "]"; |
||||
} |
||||
} |
@ -0,0 +1,326 @@ |
||||
package org.json; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/* |
||||
Copyright (c) 2006 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
/** |
||||
* JSONWriter provides a quick and convenient way of producing JSON text. |
||||
* The texts produced strictly conform to JSON syntax rules. No whitespace is |
||||
* added, so the results are ready for transmission or storage. Each instance of |
||||
* JSONWriter can produce one JSON text. |
||||
* <p> |
||||
* A JSONWriter instance provides a <code>value</code> method for appending |
||||
* values to the |
||||
* text, and a <code>key</code> |
||||
* method for adding keys before values in objects. There are <code>array</code> |
||||
* and <code>endArray</code> methods that make and bound array values, and |
||||
* <code>object</code> and <code>endObject</code> methods which make and bound |
||||
* object values. All of these methods return the JSONWriter instance, |
||||
* permitting a cascade style. For example, <pre> |
||||
* new JSONWriter(myWriter) |
||||
* .object() |
||||
* .key("JSON") |
||||
* .value("Hello, World!") |
||||
* .endObject();</pre> which writes <pre> |
||||
* {"JSON":"Hello, World!"}</pre> |
||||
* <p> |
||||
* The first method called must be <code>array</code> or <code>object</code>. |
||||
* There are no methods for adding commas or colons. JSONWriter adds them for |
||||
* you. Objects and arrays can be nested up to 200 levels deep. |
||||
* <p> |
||||
* This can sometimes be easier than using a JSONObject to build a string. |
||||
* @author JSON.org |
||||
* @version 2016-08-08 |
||||
*/ |
||||
public class JSONWriter { |
||||
private static final int maxdepth = 200; |
||||
|
||||
/** |
||||
* The comma flag determines if a comma should be output before the next |
||||
* value. |
||||
*/ |
||||
private boolean comma; |
||||
|
||||
/** |
||||
* The current mode. Values: |
||||
* 'a' (array), |
||||
* 'd' (done), |
||||
* 'i' (initial), |
||||
* 'k' (key), |
||||
* 'o' (object). |
||||
*/ |
||||
protected char mode; |
||||
|
||||
/** |
||||
* The object/array stack. |
||||
*/ |
||||
private final JSONObject stack[]; |
||||
|
||||
/** |
||||
* The stack top index. A value of 0 indicates that the stack is empty. |
||||
*/ |
||||
private int top; |
||||
|
||||
/** |
||||
* The writer that will receive the output. |
||||
*/ |
||||
protected Appendable writer; |
||||
|
||||
/** |
||||
* Make a fresh JSONWriter. It can be used to build one JSON text. |
||||
*/ |
||||
public JSONWriter(Appendable w) { |
||||
this.comma = false; |
||||
this.mode = 'i'; |
||||
this.stack = new JSONObject[maxdepth]; |
||||
this.top = 0; |
||||
this.writer = w; |
||||
} |
||||
|
||||
/** |
||||
* Append a value. |
||||
* @param string A string value. |
||||
* @return this |
||||
* @throws JSONException If the value is out of sequence. |
||||
*/ |
||||
private JSONWriter append(String string) throws JSONException { |
||||
if (string == null) { |
||||
throw new JSONException("Null pointer"); |
||||
} |
||||
if (this.mode == 'o' || this.mode == 'a') { |
||||
try { |
||||
if (this.comma && this.mode == 'a') { |
||||
this.writer.append(','); |
||||
} |
||||
this.writer.append(string); |
||||
} catch (IOException e) { |
||||
throw new JSONException(e); |
||||
} |
||||
if (this.mode == 'o') { |
||||
this.mode = 'k'; |
||||
} |
||||
this.comma = true; |
||||
return this; |
||||
} |
||||
throw new JSONException("Value out of sequence."); |
||||
} |
||||
|
||||
/** |
||||
* Begin appending a new array. All values until the balancing |
||||
* <code>endArray</code> will be appended to this array. The |
||||
* <code>endArray</code> method must be called to mark the array's end. |
||||
* @return this |
||||
* @throws JSONException If the nesting is too deep, or if the object is |
||||
* started in the wrong place (for example as a key or after the end of the |
||||
* outermost array or object). |
||||
*/ |
||||
public JSONWriter array() throws JSONException { |
||||
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { |
||||
this.push(null); |
||||
this.append("["); |
||||
this.comma = false; |
||||
return this; |
||||
} |
||||
throw new JSONException("Misplaced array."); |
||||
} |
||||
|
||||
/** |
||||
* End something. |
||||
* @param mode Mode |
||||
* @param c Closing character |
||||
* @return this |
||||
* @throws JSONException If unbalanced. |
||||
*/ |
||||
private JSONWriter end(char mode, char c) throws JSONException { |
||||
if (this.mode != mode) { |
||||
throw new JSONException(mode == 'a' |
||||
? "Misplaced endArray." |
||||
: "Misplaced endObject."); |
||||
} |
||||
this.pop(mode); |
||||
try { |
||||
this.writer.append(c); |
||||
} catch (IOException e) { |
||||
throw new JSONException(e); |
||||
} |
||||
this.comma = true; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* End an array. This method most be called to balance calls to |
||||
* <code>array</code>. |
||||
* @return this |
||||
* @throws JSONException If incorrectly nested. |
||||
*/ |
||||
public JSONWriter endArray() throws JSONException { |
||||
return this.end('a', ']'); |
||||
} |
||||
|
||||
/** |
||||
* End an object. This method most be called to balance calls to |
||||
* <code>object</code>. |
||||
* @return this |
||||
* @throws JSONException If incorrectly nested. |
||||
*/ |
||||
public JSONWriter endObject() throws JSONException { |
||||
return this.end('k', '}'); |
||||
} |
||||
|
||||
/** |
||||
* Append a key. The key will be associated with the next value. In an |
||||
* object, every value must be preceded by a key. |
||||
* @param string A key string. |
||||
* @return this |
||||
* @throws JSONException If the key is out of place. For example, keys |
||||
* do not belong in arrays or if the key is null. |
||||
*/ |
||||
public JSONWriter key(String string) throws JSONException { |
||||
if (string == null) { |
||||
throw new JSONException("Null key."); |
||||
} |
||||
if (this.mode == 'k') { |
||||
try { |
||||
this.stack[this.top - 1].putOnce(string, Boolean.TRUE); |
||||
if (this.comma) { |
||||
this.writer.append(','); |
||||
} |
||||
this.writer.append(JSONObject.quote(string)); |
||||
this.writer.append(':'); |
||||
this.comma = false; |
||||
this.mode = 'o'; |
||||
return this; |
||||
} catch (IOException e) { |
||||
throw new JSONException(e); |
||||
} |
||||
} |
||||
throw new JSONException("Misplaced key."); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Begin appending a new object. All keys and values until the balancing |
||||
* <code>endObject</code> will be appended to this object. The |
||||
* <code>endObject</code> method must be called to mark the object's end. |
||||
* @return this |
||||
* @throws JSONException If the nesting is too deep, or if the object is |
||||
* started in the wrong place (for example as a key or after the end of the |
||||
* outermost array or object). |
||||
*/ |
||||
public JSONWriter object() throws JSONException { |
||||
if (this.mode == 'i') { |
||||
this.mode = 'o'; |
||||
} |
||||
if (this.mode == 'o' || this.mode == 'a') { |
||||
this.append("{"); |
||||
this.push(new JSONObject()); |
||||
this.comma = false; |
||||
return this; |
||||
} |
||||
throw new JSONException("Misplaced object."); |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* Pop an array or object scope. |
||||
* @param c The scope to close. |
||||
* @throws JSONException If nesting is wrong. |
||||
*/ |
||||
private void pop(char c) throws JSONException { |
||||
if (this.top <= 0) { |
||||
throw new JSONException("Nesting error."); |
||||
} |
||||
char m = this.stack[this.top - 1] == null ? 'a' : 'k'; |
||||
if (m != c) { |
||||
throw new JSONException("Nesting error."); |
||||
} |
||||
this.top -= 1; |
||||
this.mode = this.top == 0 |
||||
? 'd' |
||||
: this.stack[this.top - 1] == null |
||||
? 'a' |
||||
: 'k'; |
||||
} |
||||
|
||||
/** |
||||
* Push an array or object scope. |
||||
* @param jo The scope to open. |
||||
* @throws JSONException If nesting is too deep. |
||||
*/ |
||||
private void push(JSONObject jo) throws JSONException { |
||||
if (this.top >= maxdepth) { |
||||
throw new JSONException("Nesting too deep."); |
||||
} |
||||
this.stack[this.top] = jo; |
||||
this.mode = jo == null ? 'a' : 'k'; |
||||
this.top += 1; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Append either the value <code>true</code> or the value |
||||
* <code>false</code>. |
||||
* @param b A boolean. |
||||
* @return this |
||||
* @throws JSONException |
||||
*/ |
||||
public JSONWriter value(boolean b) throws JSONException { |
||||
return this.append(b ? "true" : "false"); |
||||
} |
||||
|
||||
/** |
||||
* Append a double value. |
||||
* @param d A double. |
||||
* @return this |
||||
* @throws JSONException If the number is not finite. |
||||
*/ |
||||
public JSONWriter value(double d) throws JSONException { |
||||
return this.value(new Double(d)); |
||||
} |
||||
|
||||
/** |
||||
* Append a long value. |
||||
* @param l A long. |
||||
* @return this |
||||
* @throws JSONException |
||||
*/ |
||||
public JSONWriter value(long l) throws JSONException { |
||||
return this.append(Long.toString(l)); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Append an object value. |
||||
* @param object The object to append. It can be null, or a Boolean, Number, |
||||
* String, JSONObject, or JSONArray, or an object that implements JSONString. |
||||
* @return this |
||||
* @throws JSONException If the value is out of sequence. |
||||
*/ |
||||
public JSONWriter value(Object object) throws JSONException { |
||||
return this.append(JSONObject.valueToString(object)); |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
import java.util.Enumeration; |
||||
import java.util.Iterator; |
||||
import java.util.Properties; |
||||
|
||||
/** |
||||
* Converts a Property file data into JSONObject and back. |
||||
* @author JSON.org |
||||
* @version 2015-05-05 |
||||
*/ |
||||
public class Property { |
||||
/** |
||||
* Converts a property file object into a JSONObject. The property file object is a table of name value pairs. |
||||
* @param properties java.util.Properties |
||||
* @return JSONObject |
||||
* @throws JSONException |
||||
*/ |
||||
public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException { |
||||
JSONObject jo = new JSONObject(); |
||||
if (properties != null && !properties.isEmpty()) { |
||||
Enumeration<?> enumProperties = properties.propertyNames(); |
||||
while(enumProperties.hasMoreElements()) { |
||||
String name = (String)enumProperties.nextElement(); |
||||
jo.put(name, properties.getProperty(name)); |
||||
} |
||||
} |
||||
return jo; |
||||
} |
||||
|
||||
/** |
||||
* Converts the JSONObject into a property file object. |
||||
* @param jo JSONObject |
||||
* @return java.util.Properties |
||||
* @throws JSONException |
||||
*/ |
||||
public static Properties toProperties(JSONObject jo) throws JSONException { |
||||
Properties properties = new Properties(); |
||||
if (jo != null) { |
||||
Iterator<String> keys = jo.keys(); |
||||
while (keys.hasNext()) { |
||||
String name = keys.next(); |
||||
properties.put(name, jo.getString(name)); |
||||
} |
||||
} |
||||
return properties; |
||||
} |
||||
} |
@ -0,0 +1,621 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2015 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* This provides static methods to convert an XML text into a JSONObject, and to |
||||
* covert a JSONObject into an XML text. |
||||
* |
||||
* @author JSON.org |
||||
* @version 2016-08-10 |
||||
*/ |
||||
@SuppressWarnings("boxing") |
||||
public class XML { |
||||
/** The Character '&'. */ |
||||
public static final Character AMP = '&'; |
||||
|
||||
/** The Character '''. */ |
||||
public static final Character APOS = '\''; |
||||
|
||||
/** The Character '!'. */ |
||||
public static final Character BANG = '!'; |
||||
|
||||
/** The Character '='. */ |
||||
public static final Character EQ = '='; |
||||
|
||||
/** The Character '>'. */ |
||||
public static final Character GT = '>'; |
||||
|
||||
/** The Character '<'. */ |
||||
public static final Character LT = '<'; |
||||
|
||||
/** The Character '?'. */ |
||||
public static final Character QUEST = '?'; |
||||
|
||||
/** The Character '"'. */ |
||||
public static final Character QUOT = '"'; |
||||
|
||||
/** The Character '/'. */ |
||||
public static final Character SLASH = '/'; |
||||
|
||||
/** |
||||
* Creates an iterator for navigating Code Points in a string instead of |
||||
* characters. Once Java7 support is dropped, this can be replaced with |
||||
* <code> |
||||
* string.codePoints() |
||||
* </code> |
||||
* which is available in Java8 and above. |
||||
* |
||||
* @see <a href= |
||||
* "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a>
|
||||
*/ |
||||
private static Iterable<Integer> codePointIterator(final String string) { |
||||
return new Iterable<Integer>() { |
||||
@Override |
||||
public Iterator<Integer> iterator() { |
||||
return new Iterator<Integer>() { |
||||
private int nextIndex = 0; |
||||
private int length = string.length(); |
||||
|
||||
@Override |
||||
public boolean hasNext() { |
||||
return this.nextIndex < this.length; |
||||
} |
||||
|
||||
@Override |
||||
public Integer next() { |
||||
int result = string.codePointAt(this.nextIndex); |
||||
this.nextIndex += Character.charCount(result); |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Replace special characters with XML escapes: |
||||
* |
||||
* <pre> |
||||
* & <small>(ampersand)</small> is replaced by &amp; |
||||
* < <small>(less than)</small> is replaced by &lt; |
||||
* > <small>(greater than)</small> is replaced by &gt; |
||||
* " <small>(double quote)</small> is replaced by &quot; |
||||
* ' <small>(single quote / apostrophe)</small> is replaced by &apos; |
||||
* </pre> |
||||
* |
||||
* @param string |
||||
* The string to be escaped. |
||||
* @return The escaped string. |
||||
*/ |
||||
public static String escape(String string) { |
||||
StringBuilder sb = new StringBuilder(string.length()); |
||||
for (final int cp : codePointIterator(string)) { |
||||
switch (cp) { |
||||
case '&': |
||||
sb.append("&"); |
||||
break; |
||||
case '<': |
||||
sb.append("<"); |
||||
break; |
||||
case '>': |
||||
sb.append(">"); |
||||
break; |
||||
case '"': |
||||
sb.append("""); |
||||
break; |
||||
case '\'': |
||||
sb.append("'"); |
||||
break; |
||||
default: |
||||
if (mustEscape(cp)) { |
||||
sb.append("&#x"); |
||||
sb.append(Integer.toHexString(cp)); |
||||
sb.append(";"); |
||||
} else { |
||||
sb.appendCodePoint(cp); |
||||
} |
||||
} |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* @param cp code point to test |
||||
* @return true if the code point is not valid for an XML |
||||
*/ |
||||
private static boolean mustEscape(int cp) { |
||||
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets
|
||||
* |
||||
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] |
||||
* |
||||
* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. |
||||
*/ |
||||
// isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F)
|
||||
// all ISO control characters are out of range except tabs and new lines
|
||||
return (Character.isISOControl(cp) |
||||
&& cp != 0x9 |
||||
&& cp != 0xA |
||||
&& cp != 0xD |
||||
) || !( |
||||
// valid the range of acceptable characters that aren't control
|
||||
(cp >= 0x20 && cp <= 0xD7FF) |
||||
|| (cp >= 0xE000 && cp <= 0xFFFD) |
||||
|| (cp >= 0x10000 && cp <= 0x10FFFF) |
||||
) |
||||
; |
||||
} |
||||
|
||||
/** |
||||
* Removes XML escapes from the string. |
||||
* |
||||
* @param string |
||||
* string to remove escapes from |
||||
* @return string with converted entities |
||||
*/ |
||||
public static String unescape(String string) { |
||||
StringBuilder sb = new StringBuilder(string.length()); |
||||
for (int i = 0, length = string.length(); i < length; i++) { |
||||
char c = string.charAt(i); |
||||
if (c == '&') { |
||||
final int semic = string.indexOf(';', i); |
||||
if (semic > i) { |
||||
final String entity = string.substring(i + 1, semic); |
||||
if (entity.charAt(0) == '#') { |
||||
int cp; |
||||
if (entity.charAt(1) == 'x') { |
||||
// hex encoded unicode
|
||||
cp = Integer.parseInt(entity.substring(2), 16); |
||||
} else { |
||||
// decimal encoded unicode
|
||||
cp = Integer.parseInt(entity.substring(1)); |
||||
} |
||||
sb.appendCodePoint(cp); |
||||
} else { |
||||
if ("quot".equalsIgnoreCase(entity)) { |
||||
sb.append('"'); |
||||
} else if ("amp".equalsIgnoreCase(entity)) { |
||||
sb.append('&'); |
||||
} else if ("apos".equalsIgnoreCase(entity)) { |
||||
sb.append('\''); |
||||
} else if ("lt".equalsIgnoreCase(entity)) { |
||||
sb.append('<'); |
||||
} else if ("gt".equalsIgnoreCase(entity)) { |
||||
sb.append('>'); |
||||
} else { |
||||
sb.append('&').append(entity).append(';'); |
||||
} |
||||
} |
||||
// skip past the entity we just parsed.
|
||||
i += entity.length() + 1; |
||||
} else { |
||||
// this shouldn't happen in most cases since the parser
|
||||
// errors on unclosed enties.
|
||||
sb.append(c); |
||||
} |
||||
} else { |
||||
// not part of an entity
|
||||
sb.append(c); |
||||
} |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Throw an exception if the string contains whitespace. Whitespace is not |
||||
* allowed in tagNames and attributes. |
||||
* |
||||
* @param string |
||||
* A string. |
||||
* @throws JSONException Thrown if the string contains whitespace or is empty. |
||||
*/ |
||||
public static void noSpace(String string) throws JSONException { |
||||
int i, length = string.length(); |
||||
if (length == 0) { |
||||
throw new JSONException("Empty string."); |
||||
} |
||||
for (i = 0; i < length; i += 1) { |
||||
if (Character.isWhitespace(string.charAt(i))) { |
||||
throw new JSONException("'" + string |
||||
+ "' contains a space character."); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Scan the content following the named tag, attaching it to the context. |
||||
* |
||||
* @param x |
||||
* The XMLTokener containing the source string. |
||||
* @param context |
||||
* The JSONObject that will include the new material. |
||||
* @param name |
||||
* The tag name. |
||||
* @return true if the close tag is processed. |
||||
* @throws JSONException |
||||
*/ |
||||
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) |
||||
throws JSONException { |
||||
char c; |
||||
int i; |
||||
JSONObject jsonobject = null; |
||||
String string; |
||||
String tagName; |
||||
Object token; |
||||
|
||||
// Test for and skip past these forms:
|
||||
// <!-- ... -->
|
||||
// <! ... >
|
||||
// <![ ... ]]>
|
||||
// <? ... ?>
|
||||
// Report errors for these forms:
|
||||
// <>
|
||||
// <=
|
||||
// <<
|
||||
|
||||
token = x.nextToken(); |
||||
|
||||
// <!
|
||||
|
||||
if (token == BANG) { |
||||
c = x.next(); |
||||
if (c == '-') { |
||||
if (x.next() == '-') { |
||||
x.skipPast("-->"); |
||||
return false; |
||||
} |
||||
x.back(); |
||||
} else if (c == '[') { |
||||
token = x.nextToken(); |
||||
if ("CDATA".equals(token)) { |
||||
if (x.next() == '[') { |
||||
string = x.nextCDATA(); |
||||
if (string.length() > 0) { |
||||
context.accumulate("content", string); |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
throw x.syntaxError("Expected 'CDATA['"); |
||||
} |
||||
i = 1; |
||||
do { |
||||
token = x.nextMeta(); |
||||
if (token == null) { |
||||
throw x.syntaxError("Missing '>' after '<!'."); |
||||
} else if (token == LT) { |
||||
i += 1; |
||||
} else if (token == GT) { |
||||
i -= 1; |
||||
} |
||||
} while (i > 0); |
||||
return false; |
||||
} else if (token == QUEST) { |
||||
|
||||
// <?
|
||||
x.skipPast("?>"); |
||||
return false; |
||||
} else if (token == SLASH) { |
||||
|
||||
// Close tag </
|
||||
|
||||
token = x.nextToken(); |
||||
if (name == null) { |
||||
throw x.syntaxError("Mismatched close tag " + token); |
||||
} |
||||
if (!token.equals(name)) { |
||||
throw x.syntaxError("Mismatched " + name + " and " + token); |
||||
} |
||||
if (x.nextToken() != GT) { |
||||
throw x.syntaxError("Misshaped close tag"); |
||||
} |
||||
return true; |
||||
|
||||
} else if (token instanceof Character) { |
||||
throw x.syntaxError("Misshaped tag"); |
||||
|
||||
// Open tag <
|
||||
|
||||
} else { |
||||
tagName = (String) token; |
||||
token = null; |
||||
jsonobject = new JSONObject(); |
||||
for (;;) { |
||||
if (token == null) { |
||||
token = x.nextToken(); |
||||
} |
||||
// attribute = value
|
||||
if (token instanceof String) { |
||||
string = (String) token; |
||||
token = x.nextToken(); |
||||
if (token == EQ) { |
||||
token = x.nextToken(); |
||||
if (!(token instanceof String)) { |
||||
throw x.syntaxError("Missing value"); |
||||
} |
||||
jsonobject.accumulate(string, |
||||
keepStrings ? unescape((String)token) : stringToValue((String) token)); |
||||
token = null; |
||||
} else { |
||||
jsonobject.accumulate(string, ""); |
||||
} |
||||
|
||||
|
||||
} else if (token == SLASH) { |
||||
// Empty tag <.../>
|
||||
if (x.nextToken() != GT) { |
||||
throw x.syntaxError("Misshaped tag"); |
||||
} |
||||
if (jsonobject.length() > 0) { |
||||
context.accumulate(tagName, jsonobject); |
||||
} else { |
||||
context.accumulate(tagName, ""); |
||||
} |
||||
return false; |
||||
|
||||
} else if (token == GT) { |
||||
// Content, between <...> and </...>
|
||||
for (;;) { |
||||
token = x.nextContent(); |
||||
if (token == null) { |
||||
if (tagName != null) { |
||||
throw x.syntaxError("Unclosed tag " + tagName); |
||||
} |
||||
return false; |
||||
} else if (token instanceof String) { |
||||
string = (String) token; |
||||
if (string.length() > 0) { |
||||
jsonobject.accumulate("content", |
||||
keepStrings ? unescape(string) : stringToValue(string)); |
||||
} |
||||
|
||||
} else if (token == LT) { |
||||
// Nested element
|
||||
if (parse(x, jsonobject, tagName,keepStrings)) { |
||||
if (jsonobject.length() == 0) { |
||||
context.accumulate(tagName, ""); |
||||
} else if (jsonobject.length() == 1 |
||||
&& jsonobject.opt("content") != null) { |
||||
context.accumulate(tagName, |
||||
jsonobject.opt("content")); |
||||
} else { |
||||
context.accumulate(tagName, jsonobject); |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
throw x.syntaxError("Misshaped tag"); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This method is the same as {@link JSONObject.stringToValue(String)} |
||||
* except that this also tries to unescape String values. |
||||
* |
||||
* @param string String to convert |
||||
* @return JSON value of this string or the string |
||||
*/ |
||||
public static Object stringToValue(String string) { |
||||
Object ret = JSONObject.stringToValue(string); |
||||
if(ret instanceof String){ |
||||
return unescape((String)ret); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONObject. Some information may be lost in this transformation because |
||||
* JSON is a data format and XML is a document format. XML uses elements, |
||||
* attributes, and content text, while JSON uses unordered collections of |
||||
* name/value pairs and arrays of values. JSON does not does not like to |
||||
* distinguish between elements and attributes. Sequences of similar |
||||
* elements are represented as JSONArrays. Content text may be placed in a |
||||
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code> |
||||
* are ignored. |
||||
* |
||||
* @param string |
||||
* The source string. |
||||
* @return A JSONObject containing the structured data from the XML string. |
||||
* @throws JSONException Thrown if there is an errors while parsing the string |
||||
*/ |
||||
public static JSONObject toJSONObject(String string) throws JSONException { |
||||
return toJSONObject(string, false); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convert a well-formed (but not necessarily valid) XML string into a |
||||
* JSONObject. Some information may be lost in this transformation because |
||||
* JSON is a data format and XML is a document format. XML uses elements, |
||||
* attributes, and content text, while JSON uses unordered collections of |
||||
* name/value pairs and arrays of values. JSON does not does not like to |
||||
* distinguish between elements and attributes. Sequences of similar |
||||
* elements are represented as JSONArrays. Content text may be placed in a |
||||
* "content" member. Comments, prologs, DTDs, and <code><[ [ ]]></code> |
||||
* are ignored. |
||||
* |
||||
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to |
||||
* numbers but will instead be the exact value as seen in the XML document. |
||||
* |
||||
* @param string |
||||
* The source string. |
||||
* @param keepStrings If true, then values will not be coerced into boolean |
||||
* or numeric values and will instead be left as strings |
||||
* @return A JSONObject containing the structured data from the XML string. |
||||
* @throws JSONException Thrown if there is an errors while parsing the string |
||||
*/ |
||||
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { |
||||
JSONObject jo = new JSONObject(); |
||||
XMLTokener x = new XMLTokener(string); |
||||
while (x.more() && x.skipPast("<")) { |
||||
parse(x, jo, null, keepStrings); |
||||
} |
||||
return jo; |
||||
} |
||||
/** |
||||
* Convert a JSONObject into a well-formed, element-normal XML string. |
||||
* |
||||
* @param object |
||||
* A JSONObject. |
||||
* @return A string. |
||||
* @throws JSONException Thrown if there is an error parsing the string |
||||
*/ |
||||
public static String toString(Object object) throws JSONException { |
||||
return toString(object, null); |
||||
} |
||||
|
||||
/** |
||||
* Convert a JSONObject into a well-formed, element-normal XML string. |
||||
* |
||||
* @param object |
||||
* A JSONObject. |
||||
* @param tagName |
||||
* The optional name of the enclosing tag. |
||||
* @return A string. |
||||
* @throws JSONException Thrown if there is an error parsing the string |
||||
*/ |
||||
public static String toString(Object object, String tagName) |
||||
throws JSONException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
JSONArray ja; |
||||
JSONObject jo; |
||||
String key; |
||||
Iterator<String> keys; |
||||
String string; |
||||
Object value; |
||||
|
||||
if (object instanceof JSONObject) { |
||||
|
||||
// Emit <tagName>
|
||||
if (tagName != null) { |
||||
sb.append('<'); |
||||
sb.append(tagName); |
||||
sb.append('>'); |
||||
} |
||||
|
||||
// Loop thru the keys.
|
||||
jo = (JSONObject) object; |
||||
keys = jo.keys(); |
||||
while (keys.hasNext()) { |
||||
key = keys.next(); |
||||
value = jo.opt(key); |
||||
if (value == null) { |
||||
value = ""; |
||||
} else if (value.getClass().isArray()) { |
||||
value = new JSONArray(value); |
||||
} |
||||
string = value instanceof String ? (String) value : null; |
||||
|
||||
// Emit content in body
|
||||
if ("content".equals(key)) { |
||||
if (value instanceof JSONArray) { |
||||
ja = (JSONArray) value; |
||||
int i = 0; |
||||
for (Object val : ja) { |
||||
if (i > 0) { |
||||
sb.append('\n'); |
||||
} |
||||
sb.append(escape(val.toString())); |
||||
i++; |
||||
} |
||||
} else { |
||||
sb.append(escape(value.toString())); |
||||
} |
||||
|
||||
// Emit an array of similar keys
|
||||
|
||||
} else if (value instanceof JSONArray) { |
||||
ja = (JSONArray) value; |
||||
for (Object val : ja) { |
||||
if (val instanceof JSONArray) { |
||||
sb.append('<'); |
||||
sb.append(key); |
||||
sb.append('>'); |
||||
sb.append(toString(val)); |
||||
sb.append("</"); |
||||
sb.append(key); |
||||
sb.append('>'); |
||||
} else { |
||||
sb.append(toString(val, key)); |
||||
} |
||||
} |
||||
} else if ("".equals(value)) { |
||||
sb.append('<'); |
||||
sb.append(key); |
||||
sb.append("/>"); |
||||
|
||||
// Emit a new tag <k>
|
||||
|
||||
} else { |
||||
sb.append(toString(value, key)); |
||||
} |
||||
} |
||||
if (tagName != null) { |
||||
|
||||
// Emit the </tagname> close tag
|
||||
sb.append("</"); |
||||
sb.append(tagName); |
||||
sb.append('>'); |
||||
} |
||||
return sb.toString(); |
||||
|
||||
} |
||||
|
||||
if (object != null) { |
||||
if (object.getClass().isArray()) { |
||||
object = new JSONArray(object); |
||||
} |
||||
|
||||
if (object instanceof JSONArray) { |
||||
ja = (JSONArray) object; |
||||
for (Object val : ja) { |
||||
// XML does not have good support for arrays. If an array
|
||||
// appears in a place where XML is lacking, synthesize an
|
||||
// <array> element.
|
||||
sb.append(toString(val, tagName == null ? "array" : tagName)); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
} |
||||
|
||||
string = (object == null) ? "null" : escape(object.toString()); |
||||
return (tagName == null) ? "\"" + string + "\"" |
||||
: (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName |
||||
+ ">" + string + "</" + tagName + ">"; |
||||
|
||||
} |
||||
} |
@ -0,0 +1,365 @@ |
||||
package org.json; |
||||
|
||||
/* |
||||
Copyright (c) 2002 JSON.org |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
The Software shall be used for Good, not Evil. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
|
||||
/** |
||||
* The XMLTokener extends the JSONTokener to provide additional methods |
||||
* for the parsing of XML texts. |
||||
* @author JSON.org |
||||
* @version 2015-12-09 |
||||
*/ |
||||
public class XMLTokener extends JSONTokener { |
||||
|
||||
|
||||
/** The table of entity values. It initially contains Character values for |
||||
* amp, apos, gt, lt, quot. |
||||
*/ |
||||
public static final java.util.HashMap<String, Character> entity; |
||||
|
||||
static { |
||||
entity = new java.util.HashMap<String, Character>(8); |
||||
entity.put("amp", XML.AMP); |
||||
entity.put("apos", XML.APOS); |
||||
entity.put("gt", XML.GT); |
||||
entity.put("lt", XML.LT); |
||||
entity.put("quot", XML.QUOT); |
||||
} |
||||
|
||||
/** |
||||
* Construct an XMLTokener from a string. |
||||
* @param s A source string. |
||||
*/ |
||||
public XMLTokener(String s) { |
||||
super(s); |
||||
} |
||||
|
||||
/** |
||||
* Get the text in the CDATA block. |
||||
* @return The string up to the <code>]]></code>. |
||||
* @throws JSONException If the <code>]]></code> is not found. |
||||
*/ |
||||
public String nextCDATA() throws JSONException { |
||||
char c; |
||||
int i; |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (;;) { |
||||
c = next(); |
||||
if (end()) { |
||||
throw syntaxError("Unclosed CDATA"); |
||||
} |
||||
sb.append(c); |
||||
i = sb.length() - 3; |
||||
if (i >= 0 && sb.charAt(i) == ']' && |
||||
sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { |
||||
sb.setLength(i); |
||||
return sb.toString(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the next XML outer token, trimming whitespace. There are two kinds |
||||
* of tokens: the '<' character which begins a markup tag, and the content |
||||
* text between markup tags. |
||||
* |
||||
* @return A string, or a '<' Character, or null if there is no more |
||||
* source text. |
||||
* @throws JSONException |
||||
*/ |
||||
public Object nextContent() throws JSONException { |
||||
char c; |
||||
StringBuilder sb; |
||||
do { |
||||
c = next(); |
||||
} while (Character.isWhitespace(c)); |
||||
if (c == 0) { |
||||
return null; |
||||
} |
||||
if (c == '<') { |
||||
return XML.LT; |
||||
} |
||||
sb = new StringBuilder(); |
||||
for (;;) { |
||||
if (c == '<' || c == 0) { |
||||
back(); |
||||
return sb.toString().trim(); |
||||
} |
||||
if (c == '&') { |
||||
sb.append(nextEntity(c)); |
||||
} else { |
||||
sb.append(c); |
||||
} |
||||
c = next(); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Return the next entity. These entities are translated to Characters: |
||||
* <code>& ' > < "</code>. |
||||
* @param ampersand An ampersand character. |
||||
* @return A Character or an entity String if the entity is not recognized. |
||||
* @throws JSONException If missing ';' in XML entity. |
||||
*/ |
||||
public Object nextEntity(char ampersand) throws JSONException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (;;) { |
||||
char c = next(); |
||||
if (Character.isLetterOrDigit(c) || c == '#') { |
||||
sb.append(Character.toLowerCase(c)); |
||||
} else if (c == ';') { |
||||
break; |
||||
} else { |
||||
throw syntaxError("Missing ';' in XML entity: &" + sb); |
||||
} |
||||
} |
||||
String string = sb.toString(); |
||||
Object object = entity.get(string); |
||||
return object != null ? object : ampersand + string + ";"; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Returns the next XML meta token. This is used for skipping over <!...> |
||||
* and <?...?> structures. |
||||
* @return Syntax characters (<code>< > / = ! ?</code>) are returned as |
||||
* Character, and strings and names are returned as Boolean. We don't care |
||||
* what the values actually are. |
||||
* @throws JSONException If a string is not properly closed or if the XML |
||||
* is badly structured. |
||||
*/ |
||||
public Object nextMeta() throws JSONException { |
||||
char c; |
||||
char q; |
||||
do { |
||||
c = next(); |
||||
} while (Character.isWhitespace(c)); |
||||
switch (c) { |
||||
case 0: |
||||
throw syntaxError("Misshaped meta tag"); |
||||
case '<': |
||||
return XML.LT; |
||||
case '>': |
||||
return XML.GT; |
||||
case '/': |
||||
return XML.SLASH; |
||||
case '=': |
||||
return XML.EQ; |
||||
case '!': |
||||
return XML.BANG; |
||||
case '?': |
||||
return XML.QUEST; |
||||
case '"': |
||||
case '\'': |
||||
q = c; |
||||
for (;;) { |
||||
c = next(); |
||||
if (c == 0) { |
||||
throw syntaxError("Unterminated string"); |
||||
} |
||||
if (c == q) { |
||||
return Boolean.TRUE; |
||||
} |
||||
} |
||||
default: |
||||
for (;;) { |
||||
c = next(); |
||||
if (Character.isWhitespace(c)) { |
||||
return Boolean.TRUE; |
||||
} |
||||
switch (c) { |
||||
case 0: |
||||
case '<': |
||||
case '>': |
||||
case '/': |
||||
case '=': |
||||
case '!': |
||||
case '?': |
||||
case '"': |
||||
case '\'': |
||||
back(); |
||||
return Boolean.TRUE; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the next XML Token. These tokens are found inside of angle |
||||
* brackets. It may be one of these characters: <code>/ > = ! ?</code> or it |
||||
* may be a string wrapped in single quotes or double quotes, or it may be a |
||||
* name. |
||||
* @return a String or a Character. |
||||
* @throws JSONException If the XML is not well formed. |
||||
*/ |
||||
public Object nextToken() throws JSONException { |
||||
char c; |
||||
char q; |
||||
StringBuilder sb; |
||||
do { |
||||
c = next(); |
||||
} while (Character.isWhitespace(c)); |
||||
switch (c) { |
||||
case 0: |
||||
throw syntaxError("Misshaped element"); |
||||
case '<': |
||||
throw syntaxError("Misplaced '<'"); |
||||
case '>': |
||||
return XML.GT; |
||||
case '/': |
||||
return XML.SLASH; |
||||
case '=': |
||||
return XML.EQ; |
||||
case '!': |
||||
return XML.BANG; |
||||
case '?': |
||||
return XML.QUEST; |
||||
|
||||
// Quoted string
|
||||
|
||||
case '"': |
||||
case '\'': |
||||
q = c; |
||||
sb = new StringBuilder(); |
||||
for (;;) { |
||||
c = next(); |
||||
if (c == 0) { |
||||
throw syntaxError("Unterminated string"); |
||||
} |
||||
if (c == q) { |
||||
return sb.toString(); |
||||
} |
||||
if (c == '&') { |
||||
sb.append(nextEntity(c)); |
||||
} else { |
||||
sb.append(c); |
||||
} |
||||
} |
||||
default: |
||||
|
||||
// Name
|
||||
|
||||
sb = new StringBuilder(); |
||||
for (;;) { |
||||
sb.append(c); |
||||
c = next(); |
||||
if (Character.isWhitespace(c)) { |
||||
return sb.toString(); |
||||
} |
||||
switch (c) { |
||||
case 0: |
||||
return sb.toString(); |
||||
case '>': |
||||
case '/': |
||||
case '=': |
||||
case '!': |
||||
case '?': |
||||
case '[': |
||||
case ']': |
||||
back(); |
||||
return sb.toString(); |
||||
case '<': |
||||
case '"': |
||||
case '\'': |
||||
throw syntaxError("Bad character in a name"); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Skip characters until past the requested string. |
||||
* If it is not found, we are left at the end of the source with a result of false. |
||||
* @param to A string to skip past. |
||||
* @throws JSONException |
||||
*/ |
||||
public boolean skipPast(String to) throws JSONException { |
||||
boolean b; |
||||
char c; |
||||
int i; |
||||
int j; |
||||
int offset = 0; |
||||
int length = to.length(); |
||||
char[] circle = new char[length]; |
||||
|
||||
/* |
||||
* First fill the circle buffer with as many characters as are in the |
||||
* to string. If we reach an early end, bail. |
||||
*/ |
||||
|
||||
for (i = 0; i < length; i += 1) { |
||||
c = next(); |
||||
if (c == 0) { |
||||
return false; |
||||
} |
||||
circle[i] = c; |
||||
} |
||||
|
||||
/* We will loop, possibly for all of the remaining characters. */ |
||||
|
||||
for (;;) { |
||||
j = offset; |
||||
b = true; |
||||
|
||||
/* Compare the circle buffer with the to string. */ |
||||
|
||||
for (i = 0; i < length; i += 1) { |
||||
if (circle[j] != to.charAt(i)) { |
||||
b = false; |
||||
break; |
||||
} |
||||
j += 1; |
||||
if (j >= length) { |
||||
j -= length; |
||||
} |
||||
} |
||||
|
||||
/* If we exit the loop with b intact, then victory is ours. */ |
||||
|
||||
if (b) { |
||||
return true; |
||||
} |
||||
|
||||
/* Get the next character. If there isn't one, then defeat is ours. */ |
||||
|
||||
c = next(); |
||||
if (c == 0) { |
||||
return false; |
||||
} |
||||
/* |
||||
* Shove the character in the circle buffer and advance the |
||||
* circle offset. The offset is mod n. |
||||
*/ |
||||
circle[offset] = c; |
||||
offset += 1; |
||||
if (offset >= length) { |
||||
offset -= length; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
package sig; |
||||
|
||||
public class Result { |
||||
String songName; |
||||
String difficulty; |
||||
int cool,fine,safe,sad,worst; |
||||
float percent; |
||||
boolean fail; |
||||
public Result(String song,String diff,int cool,int fine,int safe,int sad,int worst,float percent) { |
||||
this.songName=song; |
||||
this.difficulty=diff; |
||||
this.cool=cool; |
||||
this.fine=fine; |
||||
this.safe=safe; |
||||
this.sad=sad; |
||||
this.worst=worst; |
||||
this.percent=percent; |
||||
} |
||||
public Result(String song,String diff,int cool,int fine,int safe,int sad,int worst,float percent,boolean fail) { |
||||
this(song,diff,cool,fine,safe,sad,worst,percent); |
||||
this.fail=fail; |
||||
} |
||||
public String display() { |
||||
return new StringBuilder(Integer.toString(cool)).append("/").append(fine) |
||||
.append("/").append(safe).append("/").append(sad).append("/").append(worst).append(" ").append(percent).append("%").toString(); |
||||
} |
||||
} |
@ -0,0 +1,351 @@ |
||||
package sig; |
||||
import java.awt.Color; |
||||
import java.awt.Graphics2D; |
||||
import java.awt.Image; |
||||
import java.awt.Point; |
||||
import java.awt.Rectangle; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.WritableRaster; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import javax.imageio.ImageIO; |
||||
|
||||
import sig.utils.FileUtils; |
||||
import sig.utils.ImageUtils; |
||||
|
||||
public class TypeFace { |
||||
final static int WIDTH = 32; |
||||
final static int HEIGHT = 32; |
||||
final static int NUMBER_COUNT = 10; |
||||
public int blue_minthreshold = 75; |
||||
public int green_minthreshold = 0; |
||||
public int red_minthreshold = 0; |
||||
public int blue_maxthreshold = 255; |
||||
public int green_maxthreshold = 150; |
||||
public int red_maxthreshold = 126; |
||||
public int blue_fillminthreshold = 75; |
||||
public int green_fillminthreshold = 0; |
||||
public int red_fillminthreshold = 0; |
||||
public int blue_fillmaxthreshold = 255; |
||||
public int green_fillmaxthreshold = 150; |
||||
public int red_fillmaxthreshold = 107; |
||||
public boolean darkFillCheck = true; |
||||
Color[][] numbers = new Color[WIDTH*HEIGHT][NUMBER_COUNT]; |
||||
BufferedImage baseImg; |
||||
public TypeFace(BufferedImage img) { |
||||
this.baseImg = img; |
||||
for (int k=0;k<NUMBER_COUNT;k++) { |
||||
for (int i=0;i<WIDTH;i++) { |
||||
for (int j=0;j<HEIGHT;j++) { |
||||
numbers[i*HEIGHT+j][k]=new Color(baseImg.getRGB(i+k*WIDTH, j),true); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public int extractNumbersFromImage(BufferedImage img,File saveLoc) { |
||||
if (!saveLoc.exists()) { |
||||
saveLoc.mkdirs(); |
||||
} |
||||
|
||||
int midY = img.getHeight()/2; |
||||
int X = 0; |
||||
|
||||
String extractedNumbers = ""; |
||||
|
||||
int state = 0; |
||||
|
||||
BufferedImage numberImg = null; |
||||
|
||||
final boolean DEBUG_IMG = false; |
||||
|
||||
|
||||
int iterations=0; |
||||
while (X<img.getWidth()) { |
||||
boolean success=true; |
||||
Color p = new Color(img.getRGB(X, midY),true); |
||||
switch (state) { |
||||
case 0:{ |
||||
//Search for a dark pixel.
|
||||
if (p.getBlue()>blue_minthreshold && p.getBlue()<blue_maxthreshold && |
||||
p.getGreen()>green_minthreshold && p.getGreen()<green_maxthreshold && |
||||
p.getRed()>red_minthreshold && p.getRed()<red_maxthreshold) { |
||||
//We found a dark pixel.
|
||||
state=1; |
||||
if (DEBUG_IMG) { |
||||
try { |
||||
BufferedImage img2 = ImageUtils.toCompatibleImage(ImageUtils.copyBufferedImage(img)); |
||||
img2.setRGB(X, midY, Color.RED.getRGB()); |
||||
ImageIO.write(img2,"png",new File("stage1_"+System.currentTimeMillis()+".png")); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
if (darkFillCheck) { |
||||
success = fillDark(img,X,midY,0,0); |
||||
if (!success) { |
||||
//We're done.
|
||||
X=img.getWidth(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
}break; |
||||
case 1:{ |
||||
//Move right until light pixel.
|
||||
if (p.getBlue()>200 && p.getGreen()>200 && p.getRed()>200) { |
||||
state=2; |
||||
if (DEBUG_IMG) { |
||||
try { |
||||
BufferedImage img2 = ImageUtils.toCompatibleImage(ImageUtils.copyBufferedImage(img)); |
||||
img2.setRGB(X, midY, Color.RED.getRGB()); |
||||
ImageIO.write(img2,"png",new File("stage2_"+System.currentTimeMillis()+".png")); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
}break; |
||||
case 2:{ |
||||
//Fill algorithm until entire number is filled.
|
||||
ImgRectangle i = new ImgRectangle(); |
||||
success = fill(img,X,midY,0,0,i); |
||||
if (!success) { |
||||
//We're done.
|
||||
X=img.getWidth(); |
||||
break; |
||||
} else { |
||||
X+=i.maxX-1; |
||||
numberImg = i.createImage(); |
||||
//X+=numberImg.getWidth();
|
||||
state=3; |
||||
if (DEBUG_IMG) { |
||||
try { |
||||
BufferedImage img2 = ImageUtils.toCompatibleImage(ImageUtils.copyBufferedImage(img)); |
||||
img2.setRGB(X, midY, Color.RED.getRGB()); |
||||
ImageIO.write(img2,"png",new File("stage3_"+System.currentTimeMillis()+".png")); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
}break; |
||||
case 3:{ |
||||
//Figure out which number in the typeface it best represents.
|
||||
numberImg = ImageUtils.toCompatibleImage(ImageUtils.toBufferedImage(numberImg.getScaledInstance(WIDTH, HEIGHT, Image.SCALE_FAST))); |
||||
//System.out.println(numberImg.getWidth()+"x"+numberImg.getHeight());
|
||||
int[] hits = new int[NUMBER_COUNT]; |
||||
double highestRatio = 0; |
||||
int highest = 0; |
||||
for (int k=0;k<NUMBER_COUNT;k++) { |
||||
BufferedImage img2 = ImageUtils.toCompatibleImage(ImageUtils.copyBufferedImage(numberImg)); |
||||
for (int i=0;i<WIDTH;i++) { |
||||
for (int j=0;j<HEIGHT;j++) { |
||||
if (i<numberImg.getWidth() && |
||||
j<numberImg.getHeight()) { |
||||
Color pixel = new Color(numberImg.getRGB(i, j)); |
||||
if (numbers[i*HEIGHT+j][k].getRed()==pixel.getRed() && numbers[i*HEIGHT+j][k].getGreen()==pixel.getGreen() && numbers[i*HEIGHT+j][k].getBlue()==pixel.getBlue()) { |
||||
hits[k]++; |
||||
//System.out.println("Hit for "+((k+1)%NUMBER_COUNT)+"! "+hits[k] + "/"+numbers[i*HEIGHT+j][k]+"/"+pixel);
|
||||
if ((double)hits[k]/(WIDTH*HEIGHT)>highestRatio) { |
||||
highestRatio= (double)(hits[k])/(WIDTH*HEIGHT); |
||||
highest=k; |
||||
} |
||||
} else { |
||||
if (pixel.equals(Color.WHITE)) { |
||||
img2.setRGB(i, j, Color.BLUE.getRGB()); |
||||
} else { |
||||
img2.setRGB(i, j, Color.RED.getRGB()); |
||||
} |
||||
//FileUtils.logToFile("Pixel difference: "+numbers[i*HEIGHT+j][k]+"/"+pixel, new File(saveLoc,(iterations)+".txt").getPath());
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
FileUtils.logToFile(((k+1)%NUMBER_COUNT)+":"+((double)(hits[k])/(WIDTH*HEIGHT)), new File(saveLoc,(iterations)+".txt").getPath()); |
||||
try { |
||||
ImageIO.write(img2,"png",new File(saveLoc,(iterations)+"_"+((k+1)%NUMBER_COUNT)+".png")); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
//System.out.println("Matches closest to "+((highest+1)%NUMBER_COUNT)+" with "+highestRatio);
|
||||
iterations++; |
||||
extractedNumbers+=Integer.toString((highest+1)%NUMBER_COUNT); |
||||
state=4; |
||||
}break; |
||||
case 4:{ |
||||
//Find dark pixels again.
|
||||
if (p.getBlue()>blue_minthreshold && p.getBlue()<blue_maxthreshold && |
||||
p.getGreen()>green_minthreshold && p.getGreen()<green_maxthreshold && |
||||
p.getRed()>red_minthreshold && p.getRed()<red_maxthreshold) { |
||||
//We found a dark pixel. Back to the start.
|
||||
state=0; |
||||
if (DEBUG_IMG) { |
||||
try { |
||||
BufferedImage img2 = ImageUtils.toCompatibleImage(ImageUtils.copyBufferedImage(img)); |
||||
img2.setRGB(X, midY, Color.RED.getRGB()); |
||||
ImageIO.write(img2,"png",new File("stage4_"+System.currentTimeMillis()+".png")); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
}break; |
||||
} |
||||
X++; |
||||
} |
||||
//System.out.println("Got "+extractedNumbers);
|
||||
if (extractedNumbers.length()==0) { |
||||
return -1; |
||||
} else { |
||||
return Integer.parseInt(extractedNumbers); |
||||
} |
||||
} |
||||
|
||||
public boolean fillDark(BufferedImage img,int startX,int startY,int x,int y) { |
||||
//rect.AddPixel(new Point(x,y), Color.BLACK);
|
||||
img.setRGB(startX+x, startY+y, Color.BLACK.getRGB()); |
||||
Color p = null; |
||||
if (startX+x+1<img.getWidth()) { |
||||
p = new Color(img.getRGB(startX+x+1, startY+y)); |
||||
if (p.getBlue()>blue_fillminthreshold && p.getBlue()<blue_fillmaxthreshold && |
||||
p.getGreen()>green_fillminthreshold && p.getGreen()<green_fillmaxthreshold && |
||||
p.getRed()>red_fillminthreshold && p.getRed()<red_fillmaxthreshold) { |
||||
fillDark(img,startX,startY,x+1,y); |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
if (startX+x-1>0) { |
||||
p = new Color(img.getRGB(startX+x-1, startY+y)); |
||||
if (p.getBlue()>blue_fillminthreshold && p.getBlue()<blue_fillmaxthreshold && |
||||
p.getGreen()>green_fillminthreshold && p.getGreen()<green_fillmaxthreshold && |
||||
p.getRed()>red_fillminthreshold && p.getRed()<red_fillmaxthreshold) { |
||||
fillDark(img,startX,startY,x-1,y); |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
if (startY+y+1<img.getHeight()) { |
||||
p = new Color(img.getRGB(startX+x, startY+y+1)); |
||||
if (p.getBlue()>blue_fillminthreshold && p.getBlue()<blue_fillmaxthreshold && |
||||
p.getGreen()>green_fillminthreshold && p.getGreen()<green_fillmaxthreshold && |
||||
p.getRed()>red_fillminthreshold && p.getRed()<red_fillmaxthreshold) { |
||||
fillDark(img,startX,startY,x,y+1); |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
if (startY+y-1>0) { |
||||
p = new Color(img.getRGB(startX+x, startY+y-1)); |
||||
if (p.getBlue()>blue_fillminthreshold && p.getBlue()<blue_fillmaxthreshold && |
||||
p.getGreen()>green_fillminthreshold && p.getGreen()<green_fillmaxthreshold && |
||||
p.getRed()>red_fillminthreshold && p.getRed()<red_fillmaxthreshold) { |
||||
fillDark(img,startX,startY,x,y-1); |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public boolean fill(BufferedImage img,int startX,int startY,int x,int y,ImgRectangle rect) { |
||||
rect.AddPixel(new Point(x,y), Color.BLACK); |
||||
img.setRGB(startX+x, startY+y, Color.BLACK.getRGB()); |
||||
Color p = null; |
||||
if (startX+x+1<img.getWidth()) { |
||||
p = new Color(img.getRGB(startX+x+1, startY+y)); |
||||
if (p.getBlue()>200 && p.getGreen()>200 && p.getRed()>200) { |
||||
fill(img,startX,startY,x+1,y,rect); |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
if (startX+x-1>0) { |
||||
p = new Color(img.getRGB(startX+x-1, startY+y)); |
||||
if (p.getBlue()>200 && p.getGreen()>200 && p.getRed()>200) { |
||||
fill(img,startX,startY,x-1,y,rect); |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
if (startY+y+1<img.getHeight()) { |
||||
p = new Color(img.getRGB(startX+x, startY+y+1)); |
||||
if (p.getBlue()>200 && p.getGreen()>200 && p.getRed()>200) { |
||||
fill(img,startX,startY,x,y+1,rect); |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
if (startY+y-1>0) { |
||||
p = new Color(img.getRGB(startX+x, startY+y-1)); |
||||
if (p.getBlue()>200 && p.getGreen()>200 && p.getRed()>200) { |
||||
fill(img,startX,startY,x,y-1,rect); |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
|
||||
class ImgRectangle{ |
||||
int minX=0,maxX=0,minY=0,maxY=0; |
||||
List<Pixel> p = new ArrayList<Pixel>(); |
||||
void AddPixel(Point p, Color c) { |
||||
this.p.add(new Pixel(p,c)); |
||||
if (p.x<minX) { |
||||
minX=p.x; |
||||
} |
||||
if (p.x>maxX) { |
||||
maxX=p.x; |
||||
} |
||||
if (p.y<minY) { |
||||
minY=p.y; |
||||
} |
||||
if (p.y>maxY) { |
||||
maxY=p.y; |
||||
} |
||||
} |
||||
BufferedImage createImage() { |
||||
int finalWidth = maxX-minX+1; |
||||
int offsetX = 0; |
||||
int finalHeight = maxY-minY+1; |
||||
int offsetY = 0; |
||||
/*if (finalWidth > finalHeight) { |
||||
//Add padding for height.
|
||||
offsetY += (finalWidth-finalHeight)/2; |
||||
finalHeight+= offsetY*2; |
||||
} |
||||
if (finalHeight > finalWidth) { |
||||
//Add padding for width.
|
||||
offsetX += (finalHeight-finalWidth)/2; |
||||
finalWidth+= offsetX*2; |
||||
}*/ |
||||
|
||||
BufferedImage bufferedImage = ImageUtils.toCompatibleImage(new BufferedImage(finalWidth, finalHeight, |
||||
BufferedImage.TYPE_INT_RGB)); |
||||
Graphics2D graphics = bufferedImage.createGraphics(); |
||||
graphics.setPaint ( new Color ( 255, 255, 255 ) ); |
||||
graphics.fillRect ( 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight() ); |
||||
for (Pixel pixel : p) { |
||||
bufferedImage.setRGB(pixel.p.x-minX+offsetX, pixel.p.y-minY+offsetY, pixel.c.getRGB()); |
||||
} |
||||
return bufferedImage; |
||||
} |
||||
} |
||||
|
||||
|
||||
class Pixel{ |
||||
Point p; |
||||
Color c; |
||||
Pixel(Point p,Color c) { |
||||
this.p=p; |
||||
this.c=c; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,219 @@ |
||||
package sig.utils; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import javax.sound.sampled.AudioSystem; |
||||
import javax.sound.sampled.BooleanControl; |
||||
import javax.sound.sampled.CompoundControl; |
||||
import javax.sound.sampled.Control; |
||||
import javax.sound.sampled.Control.Type; |
||||
import javax.sound.sampled.FloatControl; |
||||
import javax.sound.sampled.Line; |
||||
import javax.sound.sampled.LineUnavailableException; |
||||
import javax.sound.sampled.Mixer; |
||||
import javax.sound.sampled.Mixer.Info; |
||||
|
||||
public class Audio { |
||||
|
||||
public static void main(String[] args) throws Exception { |
||||
System.out.println(getHierarchyInfo()); |
||||
System.out.println(getMasterOutputVolume()); |
||||
} |
||||
|
||||
public static void setMasterOutputVolume(float value) { |
||||
if (value < 0 || value > 1) |
||||
throw new IllegalArgumentException( |
||||
"Volume can only be set to a value from 0 to 1. Given value is illegal: " + value); |
||||
Line line = getMasterOutputLine(); |
||||
if (line == null) throw new RuntimeException("Master output port not found"); |
||||
boolean opened = open(line); |
||||
try { |
||||
FloatControl control = getVolumeControl(line); |
||||
if (control == null) |
||||
throw new RuntimeException("Volume control not found in master port: " + toString(line)); |
||||
control.setValue(value); |
||||
} finally { |
||||
if (opened) line.close(); |
||||
} |
||||
} |
||||
|
||||
public static Float getMasterOutputVolume() { |
||||
Line line = getMasterOutputLine(); |
||||
if (line == null) return null; |
||||
boolean opened = open(line); |
||||
try { |
||||
FloatControl control = getVolumeControl(line); |
||||
if (control == null) return null; |
||||
return control.getValue(); |
||||
} finally { |
||||
if (opened) line.close(); |
||||
} |
||||
} |
||||
|
||||
public static void setMasterOutputMute(boolean value) { |
||||
Line line = getMasterOutputLine(); |
||||
if (line == null) throw new RuntimeException("Master output port not found"); |
||||
boolean opened = open(line); |
||||
try { |
||||
BooleanControl control = getMuteControl(line); |
||||
if (control == null) |
||||
throw new RuntimeException("Mute control not found in master port: " + toString(line)); |
||||
control.setValue(value); |
||||
} finally { |
||||
if (opened) line.close(); |
||||
} |
||||
} |
||||
|
||||
public static Boolean getMasterOutputMute() { |
||||
Line line = getMasterOutputLine(); |
||||
if (line == null) return null; |
||||
boolean opened = open(line); |
||||
try { |
||||
BooleanControl control = getMuteControl(line); |
||||
if (control == null) return null; |
||||
return control.getValue(); |
||||
} finally { |
||||
if (opened) line.close(); |
||||
} |
||||
} |
||||
|
||||
public static Line getMasterOutputLine() { |
||||
for (Mixer mixer : getMixers()) { |
||||
for (Line line : getAvailableOutputLines(mixer)) { |
||||
if (line.getLineInfo().toString().contains("Master")) return line; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public static FloatControl getVolumeControl(Line line) { |
||||
if (!line.isOpen()) throw new RuntimeException("Line is closed: " + toString(line)); |
||||
return (FloatControl) findControl(FloatControl.Type.VOLUME, line.getControls()); |
||||
} |
||||
|
||||
public static BooleanControl getMuteControl(Line line) { |
||||
if (!line.isOpen()) throw new RuntimeException("Line is closed: " + toString(line)); |
||||
return (BooleanControl) findControl(BooleanControl.Type.MUTE, line.getControls()); |
||||
} |
||||
|
||||
private static Control findControl(Type type, Control... controls) { |
||||
if (controls == null || controls.length == 0) return null; |
||||
for (Control control : controls) { |
||||
if (control.getType().equals(type)) return control; |
||||
if (control instanceof CompoundControl) { |
||||
CompoundControl compoundControl = (CompoundControl) control; |
||||
Control member = findControl(type, compoundControl.getMemberControls()); |
||||
if (member != null) return member; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public static List<Mixer> getMixers() { |
||||
Info[] infos = AudioSystem.getMixerInfo(); |
||||
List<Mixer> mixers = new ArrayList<Mixer>(infos.length); |
||||
for (Info info : infos) { |
||||
Mixer mixer = AudioSystem.getMixer(info); |
||||
mixers.add(mixer); |
||||
} |
||||
return mixers; |
||||
} |
||||
|
||||
public static List<Line> getAvailableOutputLines(Mixer mixer) { |
||||
return getAvailableLines(mixer, mixer.getTargetLineInfo()); |
||||
} |
||||
|
||||
public static List<Line> getAvailableInputLines(Mixer mixer) { |
||||
return getAvailableLines(mixer, mixer.getSourceLineInfo()); |
||||
} |
||||
|
||||
private static List<Line> getAvailableLines(Mixer mixer, Line.Info[] lineInfos) { |
||||
List<Line> lines = new ArrayList<Line>(lineInfos.length); |
||||
for (Line.Info lineInfo : lineInfos) { |
||||
Line line; |
||||
line = getLineIfAvailable(mixer, lineInfo); |
||||
if (line != null) lines.add(line); |
||||
} |
||||
return lines; |
||||
} |
||||
|
||||
public static Line getLineIfAvailable(Mixer mixer, Line.Info lineInfo) { |
||||
try { |
||||
return mixer.getLine(lineInfo); |
||||
} catch (LineUnavailableException ex) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public static String getHierarchyInfo() { |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (Mixer mixer : getMixers()) { |
||||
sb.append("Mixer: ").append(toString(mixer)).append("\n"); |
||||
|
||||
for (Line line : getAvailableOutputLines(mixer)) { |
||||
sb.append(" OUT: ").append(toString(line)).append("\n"); |
||||
boolean opened = open(line); |
||||
for (Control control : line.getControls()) { |
||||
sb.append(" Control: ").append(toString(control)).append("\n"); |
||||
if (control instanceof CompoundControl) { |
||||
CompoundControl compoundControl = (CompoundControl) control; |
||||
for (Control subControl : compoundControl.getMemberControls()) { |
||||
sb.append(" Sub-Control: ").append(toString(subControl)).append("\n"); |
||||
} |
||||
} |
||||
} |
||||
if (opened) line.close(); |
||||
} |
||||
|
||||
for (Line line : getAvailableOutputLines(mixer)) { |
||||
sb.append(" IN: ").append(toString(line)).append("\n"); |
||||
boolean opened = open(line); |
||||
for (Control control : line.getControls()) { |
||||
sb.append(" Control: ").append(toString(control)).append("\n"); |
||||
if (control instanceof CompoundControl) { |
||||
CompoundControl compoundControl = (CompoundControl) control; |
||||
for (Control subControl : compoundControl.getMemberControls()) { |
||||
sb.append(" Sub-Control: ").append(toString(subControl)).append("\n"); |
||||
} |
||||
} |
||||
} |
||||
if (opened) line.close(); |
||||
} |
||||
|
||||
sb.append("\n"); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
public static boolean open(Line line) { |
||||
if (line.isOpen()) return false; |
||||
try { |
||||
line.open(); |
||||
} catch (LineUnavailableException ex) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public static String toString(Control control) { |
||||
if (control == null) return null; |
||||
return control.toString() + " (" + control.getType().toString() + ")"; |
||||
} |
||||
|
||||
public static String toString(Line line) { |
||||
if (line == null) return null; |
||||
Line.Info info = line.getLineInfo(); |
||||
return info.toString();// + " (" + line.getClass().getSimpleName() + ")";
|
||||
} |
||||
|
||||
public static String toString(Mixer mixer) { |
||||
if (mixer == null) return null; |
||||
StringBuilder sb = new StringBuilder(); |
||||
Info info = mixer.getMixerInfo(); |
||||
sb.append(info.getName()); |
||||
sb.append(" (").append(info.getDescription()).append(")"); |
||||
sb.append(mixer.isOpen() ? " [open]" : " [closed]"); |
||||
return sb.toString(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,17 @@ |
||||
package sig.utils; |
||||
|
||||
|
||||
public class DebugUtils { |
||||
public static void showStackTrace() { |
||||
System.out.println("Trace:"+getStackTrace()); |
||||
} |
||||
|
||||
public static String getStackTrace() { |
||||
StackTraceElement[] stacktrace = new Throwable().getStackTrace(); |
||||
StringBuilder stack = new StringBuilder("Mini stack tracer:"); |
||||
for (int i=0;i<Math.min(10, stacktrace.length);i++) { |
||||
stack.append("\n"+stacktrace[i].getClassName()+": **"+stacktrace[i].getFileName()+"** "+stacktrace[i].getMethodName()+"():"+stacktrace[i].getLineNumber()); |
||||
} |
||||
return stack.toString(); |
||||
} |
||||
} |
@ -0,0 +1,112 @@ |
||||
package sig.utils; |
||||
import java.awt.AlphaComposite; |
||||
import java.awt.BasicStroke; |
||||
import java.awt.Color; |
||||
import java.awt.Font; |
||||
import java.awt.Graphics; |
||||
import java.awt.Graphics2D; |
||||
import java.awt.Image; |
||||
import java.awt.Rectangle; |
||||
import java.awt.RenderingHints; |
||||
import java.awt.Shape; |
||||
import java.awt.font.FontRenderContext; |
||||
import java.awt.font.GlyphVector; |
||||
import java.awt.font.TextAttribute; |
||||
import java.awt.geom.Rectangle2D; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.ImageObserver; |
||||
import java.text.AttributedString; |
||||
|
||||
|
||||
public class DrawUtils { |
||||
public static void drawOutlineText(Graphics g, Font font, double x, double y, int outline_size, Color text_color, Color shadow_color, String message) { |
||||
drawOutlineText(g,font,x,y,0,0,1,outline_size,text_color,shadow_color,message); |
||||
} |
||||
public static void drawOutlineText(Graphics g, Font font, double x, double y, int font_thickness, int outline_thickness, Color text_color, Color shadow_color, String message) { |
||||
drawOutlineText(g,font,x,y,0,0,font_thickness,outline_thickness,text_color,shadow_color,message); |
||||
} |
||||
static void drawOutlineText(Graphics g, Font font, double x, double y, double xoffset, double yoffset, int font_thickness, int outline_thickness, Color text_color, Color shadow_color, String message) { |
||||
if (message.length()>0) { |
||||
AttributedString as = new AttributedString(message); |
||||
as.addAttribute(TextAttribute.FONT, font); |
||||
as.addAttribute(TextAttribute.KERNING,TextAttribute.KERNING_ON); |
||||
as.addAttribute(TextAttribute.WIDTH,TextAttribute.WIDTH_EXTENDED); |
||||
as.addAttribute(TextAttribute.TRACKING,0.5); |
||||
g.setColor(shadow_color); |
||||
Graphics2D g2 = (Graphics2D) g; |
||||
FontRenderContext frc = g2.getFontMetrics(font).getFontRenderContext(); |
||||
GlyphVector gv = font.createGlyphVector(frc, message); |
||||
Shape shape = gv.getOutline((int)(x+xoffset),(int)(y+yoffset)); |
||||
g2.setClip(null); |
||||
g2.setStroke(new BasicStroke(font_thickness + outline_thickness*2)); |
||||
g2.setColor(shadow_color); |
||||
g2.setRenderingHint( |
||||
RenderingHints.KEY_ANTIALIASING, |
||||
RenderingHints.VALUE_ANTIALIAS_ON); |
||||
g2.draw(shape); |
||||
GlyphVector gv2 = font.createGlyphVector(frc, message); |
||||
Shape shape2 = gv2.getOutline((int)(x+xoffset),(int)(y+yoffset)); |
||||
g2.setClip(null); |
||||
g2.setStroke(new BasicStroke(font_thickness)); |
||||
g2.setColor(text_color); |
||||
g2.setRenderingHint( |
||||
RenderingHints.KEY_ANTIALIASING, |
||||
RenderingHints.VALUE_ANTIALIAS_ON); |
||||
g2.draw(shape2); |
||||
g2.setColor(text_color); |
||||
g2.drawString(as.getIterator(),(int)(x+xoffset),(int)(y+yoffset)); |
||||
} |
||||
} |
||||
public static void drawHealthbar(Graphics g, Rectangle bounds, double pct, Color healthbarcol) { |
||||
g.setColor(Color.BLACK); |
||||
g.draw3DRect((int)bounds.getX(), (int)bounds.getY(), (int)bounds.getWidth(), (int)bounds.getHeight(), true); |
||||
g.setColor(healthbarcol); |
||||
g.fill3DRect((int)bounds.getX()+1, (int)bounds.getY()+1, (int)(bounds.getWidth()*pct)-1, (int)bounds.getHeight()-1, true); |
||||
} |
||||
|
||||
public static Color convertStringToColor(String s) { |
||||
String[] split = s.split(","); |
||||
if (split.length==3) { |
||||
return new Color( |
||||
Math.min(Math.abs(Integer.parseInt(split[0])),255), |
||||
Math.min(Math.abs(Integer.parseInt(split[1])),255), |
||||
Math.min(Math.abs(Integer.parseInt(split[2])),255)); |
||||
} else |
||||
if (split.length==4) { |
||||
return new Color( |
||||
Math.min(Math.abs(Integer.parseInt(split[0])),255), |
||||
Math.min(Math.abs(Integer.parseInt(split[1])),255), |
||||
Math.min(Math.abs(Integer.parseInt(split[2])),255), |
||||
Math.min(Math.abs(Integer.parseInt(split[3])),255)); |
||||
} else { |
||||
System.out.println("WARNING! Invalid Color string specified ("+s+")."); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public static void drawImage(Graphics g, Image img, double x, double y, Color blend_col, ImageObserver source) { |
||||
BufferedImage tmp = new BufferedImage(img.getWidth(source),img.getHeight(source),BufferedImage.TYPE_INT_ARGB); |
||||
Graphics2D g2 = tmp.createGraphics(); |
||||
g2.drawImage(img, 0, 0, null); |
||||
g2.setComposite(AlphaComposite.SrcAtop); |
||||
g2.setColor(blend_col); |
||||
g2.fillRect(0, 0, img.getWidth(source), img.getHeight(source)); |
||||
g2.dispose(); |
||||
g.drawImage(tmp,(int)x,(int)y,source); |
||||
} |
||||
|
||||
public static void drawImageScaled(Graphics g, Image img, double x, double y, double xsize, double ysize, Color blend_col, ImageObserver source) { |
||||
BufferedImage tmp = new BufferedImage(img.getWidth(source),img.getHeight(source),BufferedImage.TYPE_INT_ARGB); |
||||
Graphics2D g2 = tmp.createGraphics(); |
||||
g2.drawImage(img, 0, 0, null); |
||||
g2.setComposite(AlphaComposite.SrcAtop); |
||||
g2.setColor(blend_col); |
||||
g2.fillRect(0, 0, img.getWidth(source), img.getHeight(source)); |
||||
g2.dispose(); |
||||
g.drawImage(tmp,(int)x,(int)y,(int)xsize,(int)ysize,source); |
||||
} |
||||
|
||||
public static Color invertColor(Color c) { |
||||
return new Color(255-c.getRed(),255-c.getGreen(),255-c.getBlue(),255); |
||||
} |
||||
} |
@ -0,0 +1,373 @@ |
||||
package sig.utils; |
||||
import java.io.BufferedReader; |
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.FileOutputStream; |
||||
import java.io.FileReader; |
||||
import java.io.FileWriter; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.io.PrintWriter; |
||||
import java.io.Reader; |
||||
import java.net.ConnectException; |
||||
import java.net.HttpURLConnection; |
||||
import java.net.URL; |
||||
import java.net.URLEncoder; |
||||
import java.nio.channels.Channels; |
||||
import java.nio.channels.FileChannel; |
||||
import java.nio.channels.ReadableByteChannel; |
||||
import java.nio.charset.Charset; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
|
||||
import org.json.JSONArray; |
||||
import org.json.JSONException; |
||||
import org.json.JSONObject; |
||||
|
||||
public class FileUtils { |
||||
public static String[] readFromFile(String filename) { |
||||
File file = new File(filename); |
||||
//System.out.println(file.getAbsolutePath());
|
||||
List<String> contents= new ArrayList<String>(); |
||||
if (file.exists()) { |
||||
try( |
||||
FileReader fw = new FileReader(filename); |
||||
BufferedReader bw = new BufferedReader(fw);) |
||||
{ |
||||
String readline = bw.readLine(); |
||||
do { |
||||
if (readline!=null) { |
||||
//System.out.println(readline);
|
||||
contents.add(readline); |
||||
readline = bw.readLine(); |
||||
}} while (readline!=null); |
||||
fw.close(); |
||||
bw.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
return contents.toArray(new String[contents.size()]); |
||||
} |
||||
|
||||
private static String readAll(Reader rd) throws IOException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
int cp; |
||||
while ((cp = rd.read()) != -1) { |
||||
sb.append((char) cp); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
private static String readFilter(Reader rd, HashMap<Long,String> channel_ids) throws IOException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
boolean allowed=false; |
||||
boolean quotation_mark=false; |
||||
boolean endquotation_mark=false; |
||||
boolean foundChannel=false; |
||||
boolean nextBrace=false; |
||||
boolean outputStuff=false; |
||||
String numb = ""; |
||||
int braceCount=0; |
||||
int channelCount=0; |
||||
int vals=0; |
||||
int cp; |
||||
while ((cp = rd.read()) != -1) { |
||||
if (braceCount==0) { |
||||
allowed=true; |
||||
} else |
||||
if (braceCount==1 && !quotation_mark){ |
||||
quotation_mark=true; |
||||
numb=""; |
||||
allowed=false; |
||||
} else |
||||
if (!endquotation_mark) { |
||||
if ((char)cp >= '0' && |
||||
(char)cp <= '9') { |
||||
allowed=false; |
||||
numb+=(char)cp; |
||||
} else { |
||||
allowed=false; |
||||
endquotation_mark=true; |
||||
try { |
||||
if (channel_ids.containsKey(Long.parseLong(numb))) { |
||||
if (channelCount>=1) { |
||||
sb.append(","); |
||||
} |
||||
sb.append("\""+numb+"\""); |
||||
foundChannel=true; |
||||
System.out.println("Found channel "+numb); |
||||
outputStuff=true; |
||||
} |
||||
} catch (NumberFormatException e) { |
||||
|
||||
} |
||||
} |
||||
} else |
||||
if (!nextBrace && foundChannel) { |
||||
allowed=true; |
||||
if ((char)cp == '{') { |
||||
nextBrace=true; |
||||
} |
||||
} else |
||||
if (foundChannel) { |
||||
allowed=true; |
||||
if (braceCount==1) { |
||||
allowed=false; |
||||
channelCount++; |
||||
quotation_mark=false; |
||||
endquotation_mark=false; |
||||
foundChannel=false; |
||||
nextBrace=false; |
||||
} |
||||
} else { |
||||
allowed=false; |
||||
if (braceCount==1) { |
||||
allowed=false; |
||||
quotation_mark=false; |
||||
endquotation_mark=false; |
||||
foundChannel=false; |
||||
nextBrace=false; |
||||
} |
||||
} |
||||
|
||||
/*if (outputStuff && vals++<1000) { |
||||
System.out.print((char)cp); |
||||
}*/ |
||||
if ((char)cp == '{') { |
||||
braceCount++; |
||||
//System.out.println("Brace count is "+braceCount+".");
|
||||
} else |
||||
if ((char)cp == '}') { |
||||
braceCount--; |
||||
//System.out.println("Brace count is "+braceCount+".");
|
||||
} |
||||
|
||||
if (allowed) { |
||||
sb.append((char) cp); |
||||
} |
||||
} |
||||
sb.append("}"); |
||||
//System.out.println("=============");
|
||||
//System.out.println(sb.toString());
|
||||
return sb.toString(); |
||||
} |
||||
|
||||
public static JSONObject readJsonFromUrlWithFilter(String url, HashMap<Long,String> filter) throws IOException, JSONException { |
||||
return readJsonFromUrlWithFilter(url,filter,null,false); |
||||
} |
||||
|
||||
public static JSONObject readJsonFromFileWithFilter(String file, HashMap<Long,String> filter) throws IOException, JSONException { |
||||
InputStream is = new FileInputStream(new File(file)); |
||||
try { |
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); |
||||
String jsonText = readFilter(rd,filter); |
||||
JSONObject json = new JSONObject(jsonText); |
||||
jsonText=null; |
||||
return json; |
||||
} finally { |
||||
is.close(); |
||||
} |
||||
} |
||||
|
||||
public static JSONObject readJsonFromUrlWithFilter(String url, HashMap<Long,String> filter, String file, boolean writeToFile) throws IOException, JSONException { |
||||
InputStream is = new URL(url).openStream(); |
||||
try { |
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); |
||||
String jsonText = readFilter(rd,filter); |
||||
if (writeToFile) { |
||||
writetoFile(new String[]{jsonText},file); |
||||
} |
||||
JSONObject json = new JSONObject(jsonText); |
||||
return json; |
||||
} finally { |
||||
is.close(); |
||||
} |
||||
} |
||||
|
||||
public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException { |
||||
return readJsonFromUrl(url,null,false); |
||||
} |
||||
|
||||
public static JSONArray readJsonArrayFromUrl(String url) throws IOException, JSONException { |
||||
return readJsonArrayFromUrl(url,null,false); |
||||
} |
||||
|
||||
public static JSONObject readJsonFromFile(String file) throws IOException, JSONException { |
||||
InputStream is = new FileInputStream(new File(file)); |
||||
try { |
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); |
||||
String jsonText = readAll(rd); |
||||
JSONObject json = new JSONObject(jsonText); |
||||
jsonText=null; |
||||
return json; |
||||
} finally { |
||||
is.close(); |
||||
} |
||||
} |
||||
|
||||
public static JSONObject readJsonFromUrl(String url, String file, boolean writeToFile) throws IOException, JSONException { |
||||
try { |
||||
InputStream is = new URL(url).openStream(); |
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); |
||||
String jsonText = readAll(rd); |
||||
if (writeToFile) { |
||||
writetoFile(new String[]{jsonText},file); |
||||
} |
||||
JSONObject json = new JSONObject(jsonText); |
||||
is.close(); |
||||
return json; |
||||
} catch (IOException e) { |
||||
return new JSONObject("{}"); |
||||
} |
||||
} |
||||
|
||||
public static JSONArray readJsonArrayFromUrl(String url, String file, boolean writeToFile) throws IOException, JSONException { |
||||
URL obj = new URL(url); |
||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection(); |
||||
con.setRequestMethod("GET"); |
||||
int responseCode = con.getResponseCode(); |
||||
System.out.println("GET Response Code :: " + responseCode); |
||||
if (responseCode == HttpURLConnection.HTTP_OK) { // success
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader( |
||||
con.getInputStream())); |
||||
String inputLine; |
||||
StringBuffer response = new StringBuffer(); |
||||
|
||||
while ((inputLine = in.readLine()) != null) { |
||||
response.append(inputLine); |
||||
} |
||||
in.close(); |
||||
|
||||
// print result
|
||||
System.out.println(response); |
||||
|
||||
return new JSONArray(response.toString()); |
||||
} else { |
||||
System.out.println("GET request not worked"); |
||||
return new JSONArray("[]"); |
||||
} |
||||
} |
||||
|
||||
public static void logToFile(String message, String filename) { |
||||
logToFile(message,filename,false); |
||||
} |
||||
|
||||
public static void logToFile(String message, String filename, boolean outputToChatLog) { |
||||
File file = new File(filename); |
||||
try { |
||||
|
||||
if (!file.exists()) { |
||||
file.createNewFile(); |
||||
} |
||||
|
||||
FileWriter fw = new FileWriter(file, true); |
||||
PrintWriter pw = new PrintWriter(fw); |
||||
|
||||
pw.println(message); |
||||
pw.flush(); |
||||
pw.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
public static void writetoFile(String[] data, String filename) { |
||||
File file = new File(filename); |
||||
try { |
||||
|
||||
if (!file.exists()) { |
||||
file.createNewFile(); |
||||
} |
||||
|
||||
FileWriter fw = new FileWriter(file,false); |
||||
PrintWriter pw = new PrintWriter(fw); |
||||
|
||||
for (String s : data) { |
||||
pw.println(s); |
||||
} |
||||
pw.flush(); |
||||
pw.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
public static void copyFile(File source, File dest) throws IOException { |
||||
FileChannel sourceChannel = null; |
||||
FileChannel destChannel = null; |
||||
try { |
||||
sourceChannel = new FileInputStream(source).getChannel(); |
||||
destChannel = new FileOutputStream(dest).getChannel(); |
||||
destChannel.transferFrom(sourceChannel, 0, sourceChannel.size()); |
||||
}finally{ |
||||
sourceChannel.close(); |
||||
destChannel.close(); |
||||
} |
||||
} |
||||
|
||||
public static void copyFileDir(File sourcedir, File destdir) throws IOException { |
||||
FileChannel sourceChannel = null; |
||||
FileChannel destChannel = null; |
||||
destdir.mkdirs(); |
||||
try { |
||||
if (sourcedir.exists()) { |
||||
for (String name : sourcedir.list()) { |
||||
File f = new File(sourcedir,name); |
||||
sourceChannel = new FileInputStream(f).getChannel(); |
||||
destChannel = new FileOutputStream(new File(destdir,name)).getChannel(); |
||||
destChannel.transferFrom(sourceChannel, 0, sourceChannel.size()); |
||||
sourceChannel.close(); |
||||
destChannel.close(); |
||||
} |
||||
} |
||||
} |
||||
finally{ |
||||
|
||||
} |
||||
} |
||||
|
||||
public static void deleteFile(File filename) { |
||||
File file = filename; |
||||
if (file.exists()) { |
||||
//System.out.println("Trying to delete "+file);
|
||||
if (file.isDirectory()) { |
||||
for (String name : file.list()) { |
||||
File f = new File(file,name); |
||||
deleteFile(f); |
||||
} |
||||
} |
||||
file.delete(); |
||||
//System.out.println(file+" deleted");
|
||||
} |
||||
} |
||||
|
||||
public static void deleteFile(String filename) { |
||||
File file = new File(filename); |
||||
deleteFile(file); |
||||
} |
||||
|
||||
|
||||
public static void downloadFileFromUrl(String url, String file) throws IOException, JSONException { |
||||
File filer = new File(file); |
||||
filer.createNewFile(); |
||||
|
||||
URL website = new URL(url); |
||||
HttpURLConnection connection = (HttpURLConnection) website.openConnection(); |
||||
/*for (String s : connection.getHeaderFields().keySet()) { |
||||
System.out.println(s+": "+connection.getHeaderFields().get(s)); |
||||
}*/ |
||||
connection.setRequestMethod("GET"); |
||||
//connection.setRequestProperty("Content-Type", "application/json");
|
||||
try { |
||||
ReadableByteChannel rbc = Channels.newChannel(connection.getInputStream()); |
||||
FileOutputStream fos = new FileOutputStream(file); |
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); |
||||
fos.close(); |
||||
} catch (ConnectException e) { |
||||
System.out.println("Failed to connect, moving on..."); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
package sig.utils; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Arrays; |
||||
|
||||
import org.json.JSONArray; |
||||
import org.json.JSONException; |
||||
import org.json.JSONObject; |
||||
|
||||
public class GithubUtils { |
||||
public static int getSizeOfFileFromLatestGithubCommit(String filename) { |
||||
try { |
||||
JSONObject data = FileUtils.readJsonFromUrl("https://api.github.com/repos/sigonasr2/sigIRCv2"); |
||||
String url = data.getString("commits_url").replace("{/sha}", ""); |
||||
JSONArray data_array = FileUtils.readJsonArrayFromUrl(url); |
||||
JSONObject dat = data_array.getJSONObject(0); |
||||
JSONObject datapoint1 = dat.getJSONObject("commit"); |
||||
datapoint1 = datapoint1.getJSONObject("tree"); |
||||
url = datapoint1.getString("url"); |
||||
data = FileUtils.readJsonFromUrl(url); |
||||
data_array = data.getJSONArray("tree"); |
||||
for (int i=0;i<data_array.length();i++) { |
||||
JSONObject file_data = data_array.getJSONObject(i); |
||||
if (file_data.getString("path").equals(filename)) { |
||||
return file_data.getInt("size"); |
||||
} |
||||
} |
||||
} catch (JSONException e) { |
||||
e.printStackTrace(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return -1; |
||||
} |
||||
} |
@ -0,0 +1,114 @@ |
||||
package sig.utils; |
||||
|
||||
import java.awt.Graphics2D; |
||||
import java.awt.GraphicsConfiguration; |
||||
import java.awt.GraphicsEnvironment; |
||||
import java.awt.Image; |
||||
import java.awt.Rectangle; |
||||
import java.awt.image.BufferedImage; |
||||
|
||||
public class ImageUtils { |
||||
/** |
||||
* Converts a given Image into a BufferedImage |
||||
* |
||||
* @param img The Image to be converted |
||||
* @return The converted BufferedImage |
||||
*/ |
||||
public static BufferedImage toCompatibleImage(BufferedImage image) |
||||
{ |
||||
// obtain the current system graphical settings
|
||||
GraphicsConfiguration gfxConfig = GraphicsEnvironment. |
||||
getLocalGraphicsEnvironment().getDefaultScreenDevice(). |
||||
getDefaultConfiguration(); |
||||
|
||||
/* |
||||
* if image is already compatible and optimized for current system |
||||
* settings, simply return it |
||||
*/ |
||||
if (image.getColorModel().equals(gfxConfig.getColorModel())) |
||||
return image; |
||||
|
||||
// image is not optimized, so create a new image that is
|
||||
BufferedImage newImage = gfxConfig.createCompatibleImage( |
||||
image.getWidth(), image.getHeight(), image.getTransparency()); |
||||
|
||||
// get the graphics context of the new image to draw the old image on
|
||||
Graphics2D g2d = newImage.createGraphics(); |
||||
|
||||
// actually draw the image and dispose of context no longer needed
|
||||
g2d.drawImage(image, 0, 0, null); |
||||
g2d.dispose(); |
||||
|
||||
// return the new optimized image
|
||||
return newImage; |
||||
} |
||||
public static BufferedImage toBufferedImage(Image img) |
||||
{ |
||||
if (img instanceof BufferedImage) |
||||
{ |
||||
return (BufferedImage) img; |
||||
} |
||||
|
||||
// Create a buffered image with transparency
|
||||
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB); |
||||
|
||||
// Draw the image on to the buffered image
|
||||
Graphics2D bGr = bimage.createGraphics(); |
||||
bGr.drawImage(img, 0, 0, null); |
||||
bGr.dispose(); |
||||
|
||||
// Return the buffered image
|
||||
return bimage; |
||||
} |
||||
public static BufferedImage copyBufferedImage(BufferedImage img) |
||||
{ |
||||
// Create a buffered image with transparency
|
||||
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB); |
||||
|
||||
// Draw the image on to the buffered image
|
||||
Graphics2D bGr = bimage.createGraphics(); |
||||
bGr.drawImage(img, 0, 0, null); |
||||
bGr.dispose(); |
||||
|
||||
// Return the buffered image
|
||||
return bimage; |
||||
} |
||||
public static BufferedImage cropImage(BufferedImage img,Rectangle offset) |
||||
{ |
||||
// Create a buffered image with transparency
|
||||
BufferedImage bimage = new BufferedImage(offset.width, offset.height, BufferedImage.TYPE_INT_ARGB); |
||||
|
||||
// Draw the image on to the buffered image
|
||||
Graphics2D bGr = bimage.createGraphics(); |
||||
bGr.drawImage(img, -offset.x, -offset.y, null); |
||||
bGr.dispose(); |
||||
|
||||
// Return the buffered image
|
||||
return bimage; |
||||
} |
||||
public static BufferedImage copyBufferedImages(BufferedImage...img) |
||||
{ |
||||
int widthSum=0; |
||||
int maxHeight=0; |
||||
|
||||
for (int i=0;i<img.length;i++) { |
||||
widthSum+=img[i].getWidth(); |
||||
maxHeight=Math.max(maxHeight, img[i].getHeight()); |
||||
} |
||||
|
||||
// Create a buffered image with transparency
|
||||
BufferedImage bimage = new BufferedImage(widthSum, maxHeight, BufferedImage.TYPE_INT_ARGB); |
||||
|
||||
// Draw the image on to the buffered image
|
||||
Graphics2D bGr = bimage.createGraphics(); |
||||
int X=0; |
||||
for (int i=0;i<img.length;i++) { |
||||
bGr.drawImage(img[i], X, 0, null); |
||||
X+=img[i].getWidth(); |
||||
} |
||||
bGr.dispose(); |
||||
|
||||
// Return the buffered image
|
||||
return bimage; |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
package sig.utils; |
||||
|
||||
import java.lang.reflect.Field; |
||||
|
||||
public class JavaUtils { |
||||
public JavaUtils clone() { |
||||
JavaUtils newpos = new JavaUtils(); |
||||
for (Field f : this.getClass().getDeclaredFields()) { |
||||
if (ReflectUtils.isCloneable(f)) { |
||||
try { |
||||
f.set(newpos, f.get(this)); |
||||
} catch (IllegalArgumentException e) { |
||||
e.printStackTrace(); |
||||
} catch (IllegalAccessException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
return newpos; |
||||
} |
||||
public String toString() { |
||||
StringBuilder sb = new StringBuilder(); |
||||
sb.append(this.getClass().getName()+"("); |
||||
boolean first=true; |
||||
for (Field f : this.getClass().getDeclaredFields()) { |
||||
if (!first) { |
||||
sb.append(","); |
||||
} |
||||
try { |
||||
sb.append(f.getName()+"="+f.get(this)); |
||||
first=false; |
||||
} catch (IllegalArgumentException|IllegalAccessException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
sb.append(")"); |
||||
return sb.toString(); |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
package sig.utils; |
||||
|
||||
import java.lang.reflect.Field; |
||||
|
||||
public class ReflectUtils { |
||||
public static boolean isCloneable(Field f) { |
||||
int mods = f.getModifiers(); |
||||
return mods<8; |
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
package sig.utils; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
|
||||
import javax.sound.sampled.AudioInputStream; |
||||
import javax.sound.sampled.AudioSystem; |
||||
import javax.sound.sampled.Clip; |
||||
import javax.sound.sampled.LineUnavailableException; |
||||
import javax.sound.sampled.UnsupportedAudioFileException; |
||||
|
||||
public class SoundUtils { |
||||
public static void playSound(String filename) { |
||||
AudioInputStream audioInputStream; |
||||
try { |
||||
audioInputStream = AudioSystem.getAudioInputStream(new File(filename).getAbsoluteFile()); |
||||
Clip clip; |
||||
try { |
||||
clip = AudioSystem.getClip(); |
||||
clip.open(audioInputStream); |
||||
clip.start(); |
||||
} catch (LineUnavailableException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} catch (UnsupportedAudioFileException e) { |
||||
e.printStackTrace(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,85 @@ |
||||
package sig.utils; |
||||
import java.awt.Color; |
||||
import java.awt.Font; |
||||
import java.awt.Point; |
||||
import java.awt.font.FontRenderContext; |
||||
import java.awt.geom.Rectangle2D; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class TextUtils { |
||||
|
||||
public static String replaceFirst(String sourcestring, String findstring, String replacestring) { |
||||
int pos = sourcestring.indexOf(findstring); |
||||
if (pos>=0) { |
||||
String piece1 = sourcestring.substring(0,pos); |
||||
String piece2 = sourcestring.substring(pos+findstring.length(),sourcestring.length()); |
||||
//basemsg = basemsg.replaceFirst(e.getEmoteName(),e.getSpaceFiller());
|
||||
sourcestring = piece1+replacestring+piece2; |
||||
} |
||||
return sourcestring; |
||||
} |
||||
|
||||
public static boolean isAlphanumeric(String str) { |
||||
return str.matches("^[a-zA-Z0-9!\\-.?'\":,\\+ ]+$"); |
||||
} |
||||
|
||||
public static boolean isNumeric(String str) |
||||
{ |
||||
if (str.length()>0) { |
||||
return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
|
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public static boolean isInteger(String s, int radix) { |
||||
if(s.isEmpty()) return false; |
||||
for(int i = 0; i < s.length(); i++) { |
||||
if(i == 0 && s.charAt(i) == '-') { |
||||
if(s.length() == 1) return false; |
||||
else continue; |
||||
} |
||||
if(Character.digit(s.charAt(i),radix) < 0) return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public static String convertSecondsToTimeFormat(int seconds) { |
||||
StringBuilder sb = new StringBuilder(); |
||||
int sec = seconds%60; |
||||
int min = (seconds/60)%60; |
||||
int hrs = (seconds/3600)%24; |
||||
if (hrs>0) { |
||||
if (hrs>=10) { |
||||
sb.append(hrs); |
||||
} else { |
||||
sb.append(0); |
||||
sb.append(hrs); |
||||
} |
||||
sb.append(":"); |
||||
} |
||||
if (min>=10) { |
||||
sb.append(min); |
||||
} else { |
||||
sb.append(0); |
||||
sb.append(min); |
||||
} |
||||
sb.append(":"); |
||||
if (sec>=10) { |
||||
sb.append(sec); |
||||
} else { |
||||
sb.append(0); |
||||
sb.append(sec); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Converts a three CSV value to RGB value. |
||||
*/ |
||||
public static Color convertStringToColor(String col) { |
||||
String[] split = col.split(","); |
||||
return new Color(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2])); |
||||
} |
||||
} |
@ -0,0 +1,32 @@ |
||||
package sig.utils; |
||||
|
||||
import java.text.DecimalFormat; |
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
|
||||
|
||||
public class TimeUtils { |
||||
public static String GetTimeDifferenceFromCurrentDate(Date pastDate) { |
||||
long totalseconds = (Calendar.getInstance().getTimeInMillis()-pastDate.getTime())/1000; |
||||
//System.out.println("Total Seconds: "+totalseconds);
|
||||
long seconds = (long)(totalseconds); |
||||
long minutes = (long)(seconds/60); |
||||
long hours = (long)(minutes/60); |
||||
long days = (long)(hours/24); |
||||
StringBuilder string = new StringBuilder(); |
||||
DecimalFormat df = new DecimalFormat("00"); |
||||
if (days>0) { |
||||
string.append(days); |
||||
} |
||||
if (hours>0) { |
||||
string.append(((string.length()>0)?":":"")+(hours%24)); |
||||
} |
||||
if (minutes>0) { |
||||
string.append(((string.length()>0)?":":"")+df.format((minutes%60))); |
||||
} |
||||
if (seconds>0) { |
||||
string.append(((string.length()>0)?":":"")+df.format((seconds%60))); |
||||
} |
||||
return string.toString(); |
||||
} |
||||
} |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 4.7 KiB |
Loading…
Reference in new issue