parent
9035394d3d
commit
ef813e371f
@ -1,279 +0,0 @@ |
|||||||
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 covert 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 2010-12-24 |
|
||||||
*/ |
|
||||||
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) { |
|
||||||
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) { |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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(); |
|
||||||
} |
|
||||||
} |
|
@ -1,169 +0,0 @@ |
|||||||
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 2010-12-24 |
|
||||||
*/ |
|
||||||
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(); |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
int length = s.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 { |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
|
|
||||||
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(); |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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(); |
|
||||||
} |
|
||||||
} |
|
@ -1,90 +0,0 @@ |
|||||||
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 2010-12-24 |
|
||||||
*/ |
|
||||||
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 keys = jo.keys(); |
|
||||||
String string; |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
while (keys.hasNext()) { |
|
||||||
string = keys.next().toString(); |
|
||||||
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(); |
|
||||||
} |
|
||||||
} |
|
@ -1,163 +0,0 @@ |
|||||||
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 an HTTP header to a JSONObject and back. |
|
||||||
* @author JSON.org |
|
||||||
* @version 2010-12-24 |
|
||||||
*/ |
|
||||||
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().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 keys = jo.keys(); |
|
||||||
String string; |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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().toString(); |
|
||||||
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(); |
|
||||||
} |
|
||||||
} |
|
@ -1,77 +0,0 @@ |
|||||||
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 2010-12-24 |
|
||||||
*/ |
|
||||||
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; |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,920 +0,0 @@ |
|||||||
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.io.IOException; |
|
||||||
import java.io.Writer; |
|
||||||
import java.lang.reflect.Array; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* A JSONArray is an ordered sequence of values. Its external text form is a |
|
||||||
* string wrapped in square brackets with commas separating the values. The |
|
||||||
* internal form is an object having <code>get</code> and <code>opt</code> |
|
||||||
* methods for accessing the values by index, and <code>put</code> methods for |
|
||||||
* adding or replacing values. The values can be any of these types: |
|
||||||
* <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>, |
|
||||||
* <code>Number</code>, <code>String</code>, or the |
|
||||||
* <code>JSONObject.NULL object</code>. |
|
||||||
* <p> |
|
||||||
* The constructor can convert a JSON text into a Java object. The |
|
||||||
* <code>toString</code> method converts to JSON text. |
|
||||||
* <p> |
|
||||||
* A <code>get</code> method returns a value if one can be found, and throws an |
|
||||||
* exception if one cannot be found. An <code>opt</code> method returns a |
|
||||||
* default value instead of throwing an exception, and so is useful for |
|
||||||
* obtaining optional values. |
|
||||||
* <p> |
|
||||||
* The generic <code>get()</code> and <code>opt()</code> methods return an |
|
||||||
* object which you can cast or query for type. There are also typed |
|
||||||
* <code>get</code> and <code>opt</code> methods that do type checking and type |
|
||||||
* coercion for you. |
|
||||||
* <p> |
|
||||||
* The texts produced by the <code>toString</code> methods strictly conform to |
|
||||||
* JSON syntax rules. The constructors are more forgiving in the texts they will |
|
||||||
* accept: |
|
||||||
* <ul> |
|
||||||
* <li>An extra <code>,</code> <small>(comma)</small> may appear just |
|
||||||
* before the closing bracket.</li> |
|
||||||
* <li>The <code>null</code> value will be inserted when there |
|
||||||
* is <code>,</code> <small>(comma)</small> elision.</li> |
|
||||||
* <li>Strings may be quoted with <code>'</code> <small>(single |
|
||||||
* quote)</small>.</li> |
|
||||||
* <li>Strings do not need to be quoted at all if they do not begin with a quote |
|
||||||
* or single quote, and if they do not contain leading or trailing spaces, |
|
||||||
* and if they do not contain any of these characters: |
|
||||||
* <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers |
|
||||||
* and if they are not the reserved words <code>true</code>, |
|
||||||
* <code>false</code>, or <code>null</code>.</li> |
|
||||||
* <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as |
|
||||||
* well as by <code>,</code> <small>(comma)</small>.</li> |
|
||||||
* </ul> |
|
||||||
|
|
||||||
* @author JSON.org |
|
||||||
* @version 2011-12-19 |
|
||||||
*/ |
|
||||||
public class JSONArray { |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* The arrayList where the JSONArray's properties are kept. |
|
||||||
*/ |
|
||||||
private final ArrayList myArrayList; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Construct an empty JSONArray. |
|
||||||
*/ |
|
||||||
public JSONArray() { |
|
||||||
this.myArrayList = new ArrayList(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Construct a JSONArray from a JSONTokener. |
|
||||||
* @param x A JSONTokener |
|
||||||
* @throws JSONException If there is a syntax error. |
|
||||||
*/ |
|
||||||
public JSONArray(JSONTokener x) throws JSONException { |
|
||||||
this(); |
|
||||||
if (x.nextClean() != '[') { |
|
||||||
throw x.syntaxError("A JSONArray text must start with '['"); |
|
||||||
} |
|
||||||
if (x.nextClean() != ']') { |
|
||||||
x.back(); |
|
||||||
for (;;) { |
|
||||||
if (x.nextClean() == ',') { |
|
||||||
x.back(); |
|
||||||
this.myArrayList.add(JSONObject.NULL); |
|
||||||
} else { |
|
||||||
x.back(); |
|
||||||
this.myArrayList.add(x.nextValue()); |
|
||||||
} |
|
||||||
switch (x.nextClean()) { |
|
||||||
case ';': |
|
||||||
case ',': |
|
||||||
if (x.nextClean() == ']') { |
|
||||||
return; |
|
||||||
} |
|
||||||
x.back(); |
|
||||||
break; |
|
||||||
case ']': |
|
||||||
return; |
|
||||||
default: |
|
||||||
throw x.syntaxError("Expected a ',' or ']'"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Construct a JSONArray from a source JSON text. |
|
||||||
* @param source A string that begins with |
|
||||||
* <code>[</code> <small>(left bracket)</small> |
|
||||||
* and ends with <code>]</code> <small>(right bracket)</small>. |
|
||||||
* @throws JSONException If there is a syntax error. |
|
||||||
*/ |
|
||||||
public JSONArray(String source) throws JSONException { |
|
||||||
this(new JSONTokener(source)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Construct a JSONArray from a Collection. |
|
||||||
* @param collection A Collection. |
|
||||||
*/ |
|
||||||
public JSONArray(Collection collection) { |
|
||||||
this.myArrayList = new ArrayList(); |
|
||||||
if (collection != null) { |
|
||||||
Iterator iter = collection.iterator(); |
|
||||||
while (iter.hasNext()) { |
|
||||||
this.myArrayList.add(JSONObject.wrap(iter.next())); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Construct a JSONArray from an array |
|
||||||
* @throws JSONException If not an array. |
|
||||||
*/ |
|
||||||
public JSONArray(Object array) throws JSONException { |
|
||||||
this(); |
|
||||||
if (array.getClass().isArray()) { |
|
||||||
int length = Array.getLength(array); |
|
||||||
for (int i = 0; i < length; i += 1) { |
|
||||||
this.put(JSONObject.wrap(Array.get(array, i))); |
|
||||||
} |
|
||||||
} else { |
|
||||||
throw new JSONException( |
|
||||||
"JSONArray initial value should be a string or collection or array."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the object value associated with an index. |
|
||||||
* @param index |
|
||||||
* The index must be between 0 and length() - 1. |
|
||||||
* @return An object value. |
|
||||||
* @throws JSONException If there is no value for the index. |
|
||||||
*/ |
|
||||||
public Object get(int index) throws JSONException { |
|
||||||
Object object = this.opt(index); |
|
||||||
if (object == null) { |
|
||||||
throw new JSONException("JSONArray[" + index + "] not found."); |
|
||||||
} |
|
||||||
return object; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the boolean value associated with an index. |
|
||||||
* The string values "true" and "false" are converted to boolean. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return The truth. |
|
||||||
* @throws JSONException If there is no value for the index or if the |
|
||||||
* value is not convertible to boolean. |
|
||||||
*/ |
|
||||||
public boolean getBoolean(int index) throws JSONException { |
|
||||||
Object object = this.get(index); |
|
||||||
if (object.equals(Boolean.FALSE) || |
|
||||||
(object instanceof String && |
|
||||||
((String)object).equalsIgnoreCase("false"))) { |
|
||||||
return false; |
|
||||||
} else if (object.equals(Boolean.TRUE) || |
|
||||||
(object instanceof String && |
|
||||||
((String)object).equalsIgnoreCase("true"))) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
throw new JSONException("JSONArray[" + index + "] is not a boolean."); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the double value associated with an index. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return The value. |
|
||||||
* @throws JSONException If the key is not found or if the value cannot |
|
||||||
* be converted to a number. |
|
||||||
*/ |
|
||||||
public double getDouble(int index) throws JSONException { |
|
||||||
Object object = this.get(index); |
|
||||||
try { |
|
||||||
return object instanceof Number |
|
||||||
? ((Number)object).doubleValue() |
|
||||||
: Double.parseDouble((String)object); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new JSONException("JSONArray[" + index + |
|
||||||
"] is not a number."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the int value associated with an index. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return The value. |
|
||||||
* @throws JSONException If the key is not found or if the value is not a number. |
|
||||||
*/ |
|
||||||
public int getInt(int index) throws JSONException { |
|
||||||
Object object = this.get(index); |
|
||||||
try { |
|
||||||
return object instanceof Number |
|
||||||
? ((Number)object).intValue() |
|
||||||
: Integer.parseInt((String)object); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new JSONException("JSONArray[" + index + |
|
||||||
"] is not a number."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the JSONArray associated with an index. |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return A JSONArray value. |
|
||||||
* @throws JSONException If there is no value for the index. or if the |
|
||||||
* value is not a JSONArray |
|
||||||
*/ |
|
||||||
public JSONArray getJSONArray(int index) throws JSONException { |
|
||||||
Object object = this.get(index); |
|
||||||
if (object instanceof JSONArray) { |
|
||||||
return (JSONArray)object; |
|
||||||
} |
|
||||||
throw new JSONException("JSONArray[" + index + |
|
||||||
"] is not a JSONArray."); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the JSONObject associated with an index. |
|
||||||
* @param index subscript |
|
||||||
* @return A JSONObject value. |
|
||||||
* @throws JSONException If there is no value for the index or if the |
|
||||||
* value is not a JSONObject |
|
||||||
*/ |
|
||||||
public JSONObject getJSONObject(int index) throws JSONException { |
|
||||||
Object object = this.get(index); |
|
||||||
if (object instanceof JSONObject) { |
|
||||||
return (JSONObject)object; |
|
||||||
} |
|
||||||
throw new JSONException("JSONArray[" + index + |
|
||||||
"] is not a JSONObject."); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the long value associated with an index. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return The value. |
|
||||||
* @throws JSONException If the key is not found or if the value cannot |
|
||||||
* be converted to a number. |
|
||||||
*/ |
|
||||||
public long getLong(int index) throws JSONException { |
|
||||||
Object object = this.get(index); |
|
||||||
try { |
|
||||||
return object instanceof Number |
|
||||||
? ((Number)object).longValue() |
|
||||||
: Long.parseLong((String)object); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new JSONException("JSONArray[" + index + |
|
||||||
"] is not a number."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the string associated with an index. |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return A string value. |
|
||||||
* @throws JSONException If there is no string value for the index. |
|
||||||
*/ |
|
||||||
public String getString(int index) throws JSONException { |
|
||||||
Object object = this.get(index); |
|
||||||
if (object instanceof String) { |
|
||||||
return (String)object; |
|
||||||
} |
|
||||||
throw new JSONException("JSONArray[" + index + "] not a string."); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Determine if the value is null. |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return true if the value at the index is null, or if there is no value. |
|
||||||
*/ |
|
||||||
public boolean isNull(int index) { |
|
||||||
return JSONObject.NULL.equals(this.opt(index)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Make a string from the contents of this JSONArray. The |
|
||||||
* <code>separator</code> string is inserted between each element. |
|
||||||
* Warning: This method assumes that the data structure is acyclical. |
|
||||||
* @param separator A string that will be inserted between the elements. |
|
||||||
* @return a string. |
|
||||||
* @throws JSONException If the array contains an invalid number. |
|
||||||
*/ |
|
||||||
public String join(String separator) throws JSONException { |
|
||||||
int len = this.length(); |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
|
|
||||||
for (int i = 0; i < len; i += 1) { |
|
||||||
if (i > 0) { |
|
||||||
sb.append(separator); |
|
||||||
} |
|
||||||
sb.append(JSONObject.valueToString(this.myArrayList.get(i))); |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the number of elements in the JSONArray, included nulls. |
|
||||||
* |
|
||||||
* @return The length (or size). |
|
||||||
*/ |
|
||||||
public int length() { |
|
||||||
return this.myArrayList.size(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional object value associated with an index. |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return An object value, or null if there is no |
|
||||||
* object at that index. |
|
||||||
*/ |
|
||||||
public Object opt(int index) { |
|
||||||
return (index < 0 || index >= this.length()) |
|
||||||
? null |
|
||||||
: this.myArrayList.get(index); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional boolean value associated with an index. |
|
||||||
* It returns false if there is no value at that index, |
|
||||||
* or if the value is not Boolean.TRUE or the String "true". |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return The truth. |
|
||||||
*/ |
|
||||||
public boolean optBoolean(int index) { |
|
||||||
return this.optBoolean(index, false); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional boolean value associated with an index. |
|
||||||
* It returns the defaultValue if there is no value at that index or if |
|
||||||
* it is not a Boolean or the String "true" or "false" (case insensitive). |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @param defaultValue A boolean default. |
|
||||||
* @return The truth. |
|
||||||
*/ |
|
||||||
public boolean optBoolean(int index, boolean defaultValue) { |
|
||||||
try { |
|
||||||
return this.getBoolean(index); |
|
||||||
} catch (Exception e) { |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional double value associated with an index. |
|
||||||
* NaN is returned if there is no value for the index, |
|
||||||
* or if the value is not a number and cannot be converted to a number. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return The value. |
|
||||||
*/ |
|
||||||
public double optDouble(int index) { |
|
||||||
return this.optDouble(index, Double.NaN); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional double value associated with an index. |
|
||||||
* The defaultValue is returned if there is no value for the index, |
|
||||||
* or if the value is not a number and cannot be converted to a number. |
|
||||||
* |
|
||||||
* @param index subscript |
|
||||||
* @param defaultValue The default value. |
|
||||||
* @return The value. |
|
||||||
*/ |
|
||||||
public double optDouble(int index, double defaultValue) { |
|
||||||
try { |
|
||||||
return this.getDouble(index); |
|
||||||
} catch (Exception e) { |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional int value associated with an index. |
|
||||||
* Zero is returned if there is no value for the index, |
|
||||||
* or if the value is not a number and cannot be converted to a number. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return The value. |
|
||||||
*/ |
|
||||||
public int optInt(int index) { |
|
||||||
return this.optInt(index, 0); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional int value associated with an index. |
|
||||||
* The defaultValue is returned if there is no value for the index, |
|
||||||
* or if the value is not a number and cannot be converted to a number. |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @param defaultValue The default value. |
|
||||||
* @return The value. |
|
||||||
*/ |
|
||||||
public int optInt(int index, int defaultValue) { |
|
||||||
try { |
|
||||||
return this.getInt(index); |
|
||||||
} catch (Exception e) { |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional JSONArray associated with an index. |
|
||||||
* @param index subscript |
|
||||||
* @return A JSONArray value, or null if the index has no value, |
|
||||||
* or if the value is not a JSONArray. |
|
||||||
*/ |
|
||||||
public JSONArray optJSONArray(int index) { |
|
||||||
Object o = this.opt(index); |
|
||||||
return o instanceof JSONArray ? (JSONArray)o : null; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional JSONObject associated with an index. |
|
||||||
* Null is returned if the key is not found, or null if the index has |
|
||||||
* no value, or if the value is not a JSONObject. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return A JSONObject value. |
|
||||||
*/ |
|
||||||
public JSONObject optJSONObject(int index) { |
|
||||||
Object o = this.opt(index); |
|
||||||
return o instanceof JSONObject ? (JSONObject)o : null; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional long value associated with an index. |
|
||||||
* Zero is returned if there is no value for the index, |
|
||||||
* or if the value is not a number and cannot be converted to a number. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return The value. |
|
||||||
*/ |
|
||||||
public long optLong(int index) { |
|
||||||
return this.optLong(index, 0); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional long value associated with an index. |
|
||||||
* The defaultValue is returned if there is no value for the index, |
|
||||||
* or if the value is not a number and cannot be converted to a number. |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @param defaultValue The default value. |
|
||||||
* @return The value. |
|
||||||
*/ |
|
||||||
public long optLong(int index, long defaultValue) { |
|
||||||
try { |
|
||||||
return this.getLong(index); |
|
||||||
} catch (Exception e) { |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional string value associated with an index. It returns an |
|
||||||
* empty string if there is no value at that index. If the value |
|
||||||
* is not a string and is not null, then it is coverted to a string. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @return A String value. |
|
||||||
*/ |
|
||||||
public String optString(int index) { |
|
||||||
return this.optString(index, ""); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get the optional string associated with an index. |
|
||||||
* The defaultValue is returned if the key is not found. |
|
||||||
* |
|
||||||
* @param index The index must be between 0 and length() - 1. |
|
||||||
* @param defaultValue The default value. |
|
||||||
* @return A String value. |
|
||||||
*/ |
|
||||||
public String optString(int index, String defaultValue) { |
|
||||||
Object object = this.opt(index); |
|
||||||
return JSONObject.NULL.equals(object) |
|
||||||
? defaultValue |
|
||||||
: object.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Append a boolean value. This increases the array's length by one. |
|
||||||
* |
|
||||||
* @param value A boolean value. |
|
||||||
* @return this. |
|
||||||
*/ |
|
||||||
public JSONArray put(boolean value) { |
|
||||||
this.put(value ? Boolean.TRUE : Boolean.FALSE); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put a value in the JSONArray, where the value will be a |
|
||||||
* JSONArray which is produced from a Collection. |
|
||||||
* @param value A Collection value. |
|
||||||
* @return this. |
|
||||||
*/ |
|
||||||
public JSONArray put(Collection value) { |
|
||||||
this.put(new JSONArray(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Append a double value. This increases the array's length by one. |
|
||||||
* |
|
||||||
* @param value A double value. |
|
||||||
* @throws JSONException if the value is not finite. |
|
||||||
* @return this. |
|
||||||
*/ |
|
||||||
public JSONArray put(double value) throws JSONException { |
|
||||||
Double d = new Double(value); |
|
||||||
JSONObject.testValidity(d); |
|
||||||
this.put(d); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Append an int value. This increases the array's length by one. |
|
||||||
* |
|
||||||
* @param value An int value. |
|
||||||
* @return this. |
|
||||||
*/ |
|
||||||
public JSONArray put(int value) { |
|
||||||
this.put(new Integer(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Append an long value. This increases the array's length by one. |
|
||||||
* |
|
||||||
* @param value A long value. |
|
||||||
* @return this. |
|
||||||
*/ |
|
||||||
public JSONArray put(long value) { |
|
||||||
this.put(new Long(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put a value in the JSONArray, where the value will be a |
|
||||||
* JSONObject which is produced from a Map. |
|
||||||
* @param value A Map value. |
|
||||||
* @return this. |
|
||||||
*/ |
|
||||||
public JSONArray put(Map value) { |
|
||||||
this.put(new JSONObject(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Append an object value. This increases the array's length by one. |
|
||||||
* @param value An object value. The value should be a |
|
||||||
* Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the |
|
||||||
* JSONObject.NULL object. |
|
||||||
* @return this. |
|
||||||
*/ |
|
||||||
public JSONArray put(Object value) { |
|
||||||
this.myArrayList.add(value); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put or replace a boolean value in the JSONArray. If the index is greater |
|
||||||
* than the length of the JSONArray, then null elements will be added as |
|
||||||
* necessary to pad it out. |
|
||||||
* @param index The subscript. |
|
||||||
* @param value A boolean value. |
|
||||||
* @return this. |
|
||||||
* @throws JSONException If the index is negative. |
|
||||||
*/ |
|
||||||
public JSONArray put(int index, boolean value) throws JSONException { |
|
||||||
this.put(index, value ? Boolean.TRUE : Boolean.FALSE); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put a value in the JSONArray, where the value will be a |
|
||||||
* JSONArray which is produced from a Collection. |
|
||||||
* @param index The subscript. |
|
||||||
* @param value A Collection value. |
|
||||||
* @return this. |
|
||||||
* @throws JSONException If the index is negative or if the value is |
|
||||||
* not finite. |
|
||||||
*/ |
|
||||||
public JSONArray put(int index, Collection value) throws JSONException { |
|
||||||
this.put(index, new JSONArray(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put or replace a double value. If the index is greater than the length of |
|
||||||
* the JSONArray, then null elements will be added as necessary to pad |
|
||||||
* it out. |
|
||||||
* @param index The subscript. |
|
||||||
* @param value A double value. |
|
||||||
* @return this. |
|
||||||
* @throws JSONException If the index is negative or if the value is |
|
||||||
* not finite. |
|
||||||
*/ |
|
||||||
public JSONArray put(int index, double value) throws JSONException { |
|
||||||
this.put(index, new Double(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put or replace an int value. If the index is greater than the length of |
|
||||||
* the JSONArray, then null elements will be added as necessary to pad |
|
||||||
* it out. |
|
||||||
* @param index The subscript. |
|
||||||
* @param value An int value. |
|
||||||
* @return this. |
|
||||||
* @throws JSONException If the index is negative. |
|
||||||
*/ |
|
||||||
public JSONArray put(int index, int value) throws JSONException { |
|
||||||
this.put(index, new Integer(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put or replace a long value. If the index is greater than the length of |
|
||||||
* the JSONArray, then null elements will be added as necessary to pad |
|
||||||
* it out. |
|
||||||
* @param index The subscript. |
|
||||||
* @param value A long value. |
|
||||||
* @return this. |
|
||||||
* @throws JSONException If the index is negative. |
|
||||||
*/ |
|
||||||
public JSONArray put(int index, long value) throws JSONException { |
|
||||||
this.put(index, new Long(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put a value in the JSONArray, where the value will be a |
|
||||||
* JSONObject that is produced from a Map. |
|
||||||
* @param index The subscript. |
|
||||||
* @param value The Map value. |
|
||||||
* @return this. |
|
||||||
* @throws JSONException If the index is negative or if the the value is |
|
||||||
* an invalid number. |
|
||||||
*/ |
|
||||||
public JSONArray put(int index, Map value) throws JSONException { |
|
||||||
this.put(index, new JSONObject(value)); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Put or replace an object value in the JSONArray. If the index is greater |
|
||||||
* than the length of the JSONArray, then null elements will be added as |
|
||||||
* necessary to pad it out. |
|
||||||
* @param index The subscript. |
|
||||||
* @param value The value to put into the array. The value should be a |
|
||||||
* Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the |
|
||||||
* JSONObject.NULL object. |
|
||||||
* @return this. |
|
||||||
* @throws JSONException If the index is negative or if the the value is |
|
||||||
* an invalid number. |
|
||||||
*/ |
|
||||||
public JSONArray put(int index, Object value) throws JSONException { |
|
||||||
JSONObject.testValidity(value); |
|
||||||
if (index < 0) { |
|
||||||
throw new JSONException("JSONArray[" + index + "] not found."); |
|
||||||
} |
|
||||||
if (index < this.length()) { |
|
||||||
this.myArrayList.set(index, value); |
|
||||||
} else { |
|
||||||
while (index != this.length()) { |
|
||||||
this.put(JSONObject.NULL); |
|
||||||
} |
|
||||||
this.put(value); |
|
||||||
} |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Remove an index and close the hole. |
|
||||||
* @param index The index of the element to be removed. |
|
||||||
* @return The value that was associated with the index, |
|
||||||
* or null if there was no value. |
|
||||||
*/ |
|
||||||
public Object remove(int index) { |
|
||||||
Object o = this.opt(index); |
|
||||||
this.myArrayList.remove(index); |
|
||||||
return o; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Produce a JSONObject by combining a JSONArray of names with the values |
|
||||||
* of this JSONArray. |
|
||||||
* @param names A JSONArray containing a list of key strings. These will be |
|
||||||
* paired with the values. |
|
||||||
* @return A JSONObject, or null if there are no names or if this JSONArray |
|
||||||
* has no values. |
|
||||||
* @throws JSONException If any of the names are null. |
|
||||||
*/ |
|
||||||
public JSONObject toJSONObject(JSONArray names) throws JSONException { |
|
||||||
if (names == null || names.length() == 0 || this.length() == 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
JSONObject jo = new JSONObject(); |
|
||||||
for (int i = 0; i < names.length(); i += 1) { |
|
||||||
jo.put(names.getString(i), this.opt(i)); |
|
||||||
} |
|
||||||
return jo; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Make a JSON text of this JSONArray. For compactness, no |
|
||||||
* unnecessary whitespace is added. If it is not possible to produce a |
|
||||||
* syntactically correct JSON text then null will be returned instead. This |
|
||||||
* could occur if the array contains an invalid number. |
|
||||||
* <p> |
|
||||||
* Warning: This method assumes that the data structure is acyclical. |
|
||||||
* |
|
||||||
* @return a printable, displayable, transmittable |
|
||||||
* representation of the array. |
|
||||||
*/ |
|
||||||
public String toString() { |
|
||||||
try { |
|
||||||
return '[' + this.join(",") + ']'; |
|
||||||
} catch (Exception e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Make a prettyprinted JSON text of this JSONArray. |
|
||||||
* Warning: This method assumes that the data structure is acyclical. |
|
||||||
* @param indentFactor The number of spaces to add to each level of |
|
||||||
* indentation. |
|
||||||
* @return a printable, displayable, transmittable |
|
||||||
* representation of the object, beginning |
|
||||||
* with <code>[</code> <small>(left bracket)</small> and ending |
|
||||||
* with <code>]</code> <small>(right bracket)</small>. |
|
||||||
* @throws JSONException |
|
||||||
*/ |
|
||||||
public String toString(int indentFactor) throws JSONException { |
|
||||||
return this.toString(indentFactor, 0); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Make a prettyprinted JSON text of this JSONArray. |
|
||||||
* Warning: This method assumes that the data structure is acyclical. |
|
||||||
* @param indentFactor The number of spaces to add to each level of |
|
||||||
* indentation. |
|
||||||
* @param indent The indention of the top level. |
|
||||||
* @return a printable, displayable, transmittable |
|
||||||
* representation of the array. |
|
||||||
* @throws JSONException |
|
||||||
*/ |
|
||||||
String toString(int indentFactor, int indent) throws JSONException { |
|
||||||
int len = this.length(); |
|
||||||
if (len == 0) { |
|
||||||
return "[]"; |
|
||||||
} |
|
||||||
int i; |
|
||||||
StringBuffer sb = new StringBuffer("["); |
|
||||||
if (len == 1) { |
|
||||||
sb.append(JSONObject.valueToString(this.myArrayList.get(0), |
|
||||||
indentFactor, indent)); |
|
||||||
} else { |
|
||||||
int newindent = indent + indentFactor; |
|
||||||
sb.append('\n'); |
|
||||||
for (i = 0; i < len; i += 1) { |
|
||||||
if (i > 0) { |
|
||||||
sb.append(",\n"); |
|
||||||
} |
|
||||||
for (int j = 0; j < newindent; j += 1) { |
|
||||||
sb.append(' '); |
|
||||||
} |
|
||||||
sb.append(JSONObject.valueToString(this.myArrayList.get(i), |
|
||||||
indentFactor, newindent)); |
|
||||||
} |
|
||||||
sb.append('\n'); |
|
||||||
for (i = 0; i < indent; i += 1) { |
|
||||||
sb.append(' '); |
|
||||||
} |
|
||||||
} |
|
||||||
sb.append(']'); |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Write the contents of the JSONArray as JSON text to a writer. |
|
||||||
* For compactness, no whitespace is added. |
|
||||||
* <p> |
|
||||||
* Warning: This method assumes that the data structure is acyclical. |
|
||||||
* |
|
||||||
* @return The writer. |
|
||||||
* @throws JSONException |
|
||||||
*/ |
|
||||||
public Writer write(Writer writer) throws JSONException { |
|
||||||
try { |
|
||||||
boolean b = false; |
|
||||||
int len = this.length(); |
|
||||||
|
|
||||||
writer.write('['); |
|
||||||
|
|
||||||
for (int i = 0; i < len; i += 1) { |
|
||||||
if (b) { |
|
||||||
writer.write(','); |
|
||||||
} |
|
||||||
Object v = this.myArrayList.get(i); |
|
||||||
if (v instanceof JSONObject) { |
|
||||||
((JSONObject)v).write(writer); |
|
||||||
} else if (v instanceof JSONArray) { |
|
||||||
((JSONArray)v).write(writer); |
|
||||||
} else { |
|
||||||
writer.write(JSONObject.valueToString(v)); |
|
||||||
} |
|
||||||
b = true; |
|
||||||
} |
|
||||||
writer.write(']'); |
|
||||||
return writer; |
|
||||||
} catch (IOException e) { |
|
||||||
throw new JSONException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,28 +0,0 @@ |
|||||||
package org.json; |
|
||||||
|
|
||||||
/** |
|
||||||
* The JSONException is thrown by the JSON.org classes when things are amiss. |
|
||||||
* @author JSON.org |
|
||||||
* @version 2010-12-24 |
|
||||||
*/ |
|
||||||
public class JSONException extends Exception { |
|
||||||
private static final long serialVersionUID = 0; |
|
||||||
private Throwable cause; |
|
||||||
|
|
||||||
/** |
|
||||||
* Constructs a JSONException with an explanatory message. |
|
||||||
* @param message Detail about the reason for the exception. |
|
||||||
*/ |
|
||||||
public JSONException(String message) { |
|
||||||
super(message); |
|
||||||
} |
|
||||||
|
|
||||||
public JSONException(Throwable cause) { |
|
||||||
super(cause.getMessage()); |
|
||||||
this.cause = cause; |
|
||||||
} |
|
||||||
|
|
||||||
public Throwable getCause() { |
|
||||||
return this.cause; |
|
||||||
} |
|
||||||
} |
|
@ -1,465 +0,0 @@ |
|||||||
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 2011-11-24 |
|
||||||
*/ |
|
||||||
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. |
|
||||||
* @return A JSONArray if the value is the outermost tag, otherwise null. |
|
||||||
* @throws JSONException |
|
||||||
*/ |
|
||||||
private static Object parse( |
|
||||||
XMLTokener x, |
|
||||||
boolean arrayForm, |
|
||||||
JSONArray ja |
|
||||||
) 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("-->"); |
|
||||||
} |
|
||||||
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 && (attribute == "tagName" || attribute == "childNode")) { |
|
||||||
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, 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; |
|
||||||
} else { |
|
||||||
return newjo; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Content, between <...> and </...>
|
|
||||||
|
|
||||||
} else { |
|
||||||
if (token != XML.GT) { |
|
||||||
throw x.syntaxError("Misshaped tag"); |
|
||||||
} |
|
||||||
closeTag = (String)parse(x, arrayForm, newja); |
|
||||||
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; |
|
||||||
} else { |
|
||||||
return newjo; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} else { |
|
||||||
if (ja != null) { |
|
||||||
ja.put(token instanceof String |
|
||||||
? 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 |
|
||||||
*/ |
|
||||||
public static JSONArray toJSONArray(String string) throws JSONException { |
|
||||||
return toJSONArray(new XMLTokener(string)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 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 |
|
||||||
*/ |
|
||||||
public static JSONArray toJSONArray(XMLTokener x) throws JSONException { |
|
||||||
return (JSONArray)parse(x, true, null); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 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 |
|
||||||
*/ |
|
||||||
public static JSONObject toJSONObject(XMLTokener x) throws JSONException { |
|
||||||
return (JSONObject)parse(x, false, null); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 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 |
|
||||||
*/ |
|
||||||
public static JSONObject toJSONObject(String string) throws JSONException { |
|
||||||
return toJSONObject(new XMLTokener(string)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Reverse the JSONML transformation, making an XML text from a JSONArray. |
|
||||||
* @param ja A JSONArray. |
|
||||||
* @return An XML string. |
|
||||||
* @throws JSONException |
|
||||||
*/ |
|
||||||
public static String toString(JSONArray ja) throws JSONException { |
|
||||||
int i; |
|
||||||
JSONObject jo; |
|
||||||
String key; |
|
||||||
Iterator keys; |
|
||||||
int length; |
|
||||||
Object object; |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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().toString(); |
|
||||||
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)); |
|
||||||
} |
|
||||||
} |
|
||||||
} 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 |
|
||||||
*/ |
|
||||||
public static String toString(JSONObject jo) throws JSONException { |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
int i; |
|
||||||
JSONArray ja; |
|
||||||
String key; |
|
||||||
Iterator 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().toString(); |
|
||||||
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
@ -1,18 +0,0 @@ |
|||||||
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(); |
|
||||||
} |
|
@ -1,78 +0,0 @@ |
|||||||
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 2008-09-18 |
|
||||||
*/ |
|
||||||
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; |
|
||||||
} |
|
||||||
} |
|
@ -1,441 +0,0 @@ |
|||||||
package org.json; |
|
||||||
|
|
||||||
import java.io.*; |
|
||||||
|
|
||||||
/* |
|
||||||
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 2011-11-24 |
|
||||||
*/ |
|
||||||
public class JSONTokener { |
|
||||||
|
|
||||||
private int character; |
|
||||||
private boolean eof; |
|
||||||
private int index; |
|
||||||
private int line; |
|
||||||
private char previous; |
|
||||||
private final 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. |
|
||||||
*/ |
|
||||||
public JSONTokener(InputStream inputStream) throws JSONException { |
|
||||||
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. |
|
||||||
*/ |
|
||||||
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; |
|
||||||
} |
|
||||||
|
|
||||||
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. |
|
||||||
*/ |
|
||||||
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. |
|
||||||
*/ |
|
||||||
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 |
|
||||||
* @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; |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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': |
|
||||||
sb.append((char)Integer.parseInt(this.next(4), 16)); |
|
||||||
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. |
|
||||||
*/ |
|
||||||
public String nextTo(char delimiter) throws JSONException { |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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. |
|
||||||
*/ |
|
||||||
public String nextTo(String delimiters) throws JSONException { |
|
||||||
char c; |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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. |
|
||||||
*/ |
|
||||||
|
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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. |
|
||||||
*/ |
|
||||||
public char skipTo(char to) throws JSONException { |
|
||||||
char c; |
|
||||||
try { |
|
||||||
int startIndex = this.index; |
|
||||||
int startCharacter = this.character; |
|
||||||
int startLine = this.line; |
|
||||||
this.reader.mark(Integer.MAX_VALUE); |
|
||||||
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 exc) { |
|
||||||
throw new JSONException(exc); |
|
||||||
} |
|
||||||
|
|
||||||
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 printable string of this JSONTokener. |
|
||||||
* |
|
||||||
* @return " at {index} [character {character} line {line}]" |
|
||||||
*/ |
|
||||||
public String toString() { |
|
||||||
return " at " + this.index + " [character " + this.character + " line " + |
|
||||||
this.line + "]"; |
|
||||||
} |
|
||||||
} |
|
@ -1,327 +0,0 @@ |
|||||||
package org.json; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.io.Writer; |
|
||||||
|
|
||||||
/* |
|
||||||
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 20 levels deep. |
|
||||||
* <p> |
|
||||||
* This can sometimes be easier than using a JSONObject to build a string. |
|
||||||
* @author JSON.org |
|
||||||
* @version 2011-11-24 |
|
||||||
*/ |
|
||||||
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 Writer writer; |
|
||||||
|
|
||||||
/** |
|
||||||
* Make a fresh JSONWriter. It can be used to build one JSON text. |
|
||||||
*/ |
|
||||||
public JSONWriter(Writer 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.write(','); |
|
||||||
} |
|
||||||
this.writer.write(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.write(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.write(','); |
|
||||||
} |
|
||||||
this.writer.write(JSONObject.quote(string)); |
|
||||||
this.writer.write(':'); |
|
||||||
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 c 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)); |
|
||||||
} |
|
||||||
} |
|
@ -1,508 +0,0 @@ |
|||||||
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; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 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 2011-02-11 |
|
||||||
*/ |
|
||||||
public class XML { |
|
||||||
|
|
||||||
/** The Character '&'. */ |
|
||||||
public static final Character AMP = new Character('&'); |
|
||||||
|
|
||||||
/** The Character '''. */ |
|
||||||
public static final Character APOS = new Character('\''); |
|
||||||
|
|
||||||
/** The Character '!'. */ |
|
||||||
public static final Character BANG = new Character('!'); |
|
||||||
|
|
||||||
/** The Character '='. */ |
|
||||||
public static final Character EQ = new Character('='); |
|
||||||
|
|
||||||
/** The Character '>'. */ |
|
||||||
public static final Character GT = new Character('>'); |
|
||||||
|
|
||||||
/** The Character '<'. */ |
|
||||||
public static final Character LT = new Character('<'); |
|
||||||
|
|
||||||
/** The Character '?'. */ |
|
||||||
public static final Character QUEST = new Character('?'); |
|
||||||
|
|
||||||
/** The Character '"'. */ |
|
||||||
public static final Character QUOT = new Character('"'); |
|
||||||
|
|
||||||
/** The Character '/'. */ |
|
||||||
public static final Character SLASH = new Character('/'); |
|
||||||
|
|
||||||
/** |
|
||||||
* 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; |
|
||||||
* </pre> |
|
||||||
* @param string The string to be escaped. |
|
||||||
* @return The escaped string. |
|
||||||
*/ |
|
||||||
public static String escape(String string) { |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
for (int i = 0, length = string.length(); i < length; i++) { |
|
||||||
char c = string.charAt(i); |
|
||||||
switch (c) { |
|
||||||
case '&': |
|
||||||
sb.append("&"); |
|
||||||
break; |
|
||||||
case '<': |
|
||||||
sb.append("<"); |
|
||||||
break; |
|
||||||
case '>': |
|
||||||
sb.append(">"); |
|
||||||
break; |
|
||||||
case '"': |
|
||||||
sb.append("""); |
|
||||||
break; |
|
||||||
case '\'': |
|
||||||
sb.append("'"); |
|
||||||
break; |
|
||||||
default: |
|
||||||
sb.append(c); |
|
||||||
} |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Throw an exception if the string contains whitespace. |
|
||||||
* Whitespace is not allowed in tagNames and attributes. |
|
||||||
* @param string |
|
||||||
* @throws JSONException |
|
||||||
*/ |
|
||||||
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) 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, |
|
||||||
XML.stringToValue((String)token)); |
|
||||||
token = null; |
|
||||||
} else { |
|
||||||
jsonobject.accumulate(string, ""); |
|
||||||
} |
|
||||||
|
|
||||||
// Empty tag <.../>
|
|
||||||
|
|
||||||
} else if (token == SLASH) { |
|
||||||
if (x.nextToken() != GT) { |
|
||||||
throw x.syntaxError("Misshaped tag"); |
|
||||||
} |
|
||||||
if (jsonobject.length() > 0) { |
|
||||||
context.accumulate(tagName, jsonobject); |
|
||||||
} else { |
|
||||||
context.accumulate(tagName, ""); |
|
||||||
} |
|
||||||
return false; |
|
||||||
|
|
||||||
// Content, between <...> and </...>
|
|
||||||
|
|
||||||
} else if (token == GT) { |
|
||||||
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", |
|
||||||
XML.stringToValue(string)); |
|
||||||
} |
|
||||||
|
|
||||||
// Nested element
|
|
||||||
|
|
||||||
} else if (token == LT) { |
|
||||||
if (parse(x, jsonobject, tagName)) { |
|
||||||
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"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Try to convert a string into a number, boolean, or null. If the string |
|
||||||
* can't be converted, return the string. This is much less ambitious than |
|
||||||
* JSONObject.stringToValue, especially because it does not attempt to |
|
||||||
* convert plus forms, octal forms, hex forms, or E forms lacking decimal |
|
||||||
* points. |
|
||||||
* @param string A String. |
|
||||||
* @return A simple JSON value. |
|
||||||
*/ |
|
||||||
public static Object stringToValue(String string) { |
|
||||||
if ("".equals(string)) { |
|
||||||
return string; |
|
||||||
} |
|
||||||
if ("true".equalsIgnoreCase(string)) { |
|
||||||
return Boolean.TRUE; |
|
||||||
} |
|
||||||
if ("false".equalsIgnoreCase(string)) { |
|
||||||
return Boolean.FALSE; |
|
||||||
} |
|
||||||
if ("null".equalsIgnoreCase(string)) { |
|
||||||
return JSONObject.NULL; |
|
||||||
} |
|
||||||
if ("0".equals(string)) { |
|
||||||
return new Integer(0); |
|
||||||
} |
|
||||||
|
|
||||||
// If it might be a number, try converting it. If that doesn't work,
|
|
||||||
// return the string.
|
|
||||||
|
|
||||||
try { |
|
||||||
char initial = string.charAt(0); |
|
||||||
boolean negative = false; |
|
||||||
if (initial == '-') { |
|
||||||
initial = string.charAt(1); |
|
||||||
negative = true; |
|
||||||
} |
|
||||||
if (initial == '0' && string.charAt(negative ? 2 : 1) == '0') { |
|
||||||
return string; |
|
||||||
} |
|
||||||
if ((initial >= '0' && initial <= '9')) { |
|
||||||
if (string.indexOf('.') >= 0) { |
|
||||||
return Double.valueOf(string); |
|
||||||
} else if (string.indexOf('e') < 0 && string.indexOf('E') < 0) { |
|
||||||
Long myLong = new Long(string); |
|
||||||
if (myLong.longValue() == myLong.intValue()) { |
|
||||||
return new Integer(myLong.intValue()); |
|
||||||
} else { |
|
||||||
return myLong; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (Exception ignore) { |
|
||||||
} |
|
||||||
return string; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 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 |
|
||||||
*/ |
|
||||||
public static JSONObject toJSONObject(String string) throws JSONException { |
|
||||||
JSONObject jo = new JSONObject(); |
|
||||||
XMLTokener x = new XMLTokener(string); |
|
||||||
while (x.more() && x.skipPast("<")) { |
|
||||||
parse(x, jo, null); |
|
||||||
} |
|
||||||
return jo; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Convert a JSONObject into a well-formed, element-normal XML string. |
|
||||||
* @param object A JSONObject. |
|
||||||
* @return A string. |
|
||||||
* @throws JSONException |
|
||||||
*/ |
|
||||||
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 |
|
||||||
*/ |
|
||||||
public static String toString(Object object, String tagName) |
|
||||||
throws JSONException { |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
int i; |
|
||||||
JSONArray ja; |
|
||||||
JSONObject jo; |
|
||||||
String key; |
|
||||||
Iterator keys; |
|
||||||
int length; |
|
||||||
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().toString(); |
|
||||||
value = jo.opt(key); |
|
||||||
if (value == null) { |
|
||||||
value = ""; |
|
||||||
} |
|
||||||
if (value instanceof String) { |
|
||||||
string = (String)value; |
|
||||||
} else { |
|
||||||
string = null; |
|
||||||
} |
|
||||||
|
|
||||||
// Emit content in body
|
|
||||||
|
|
||||||
if ("content".equals(key)) { |
|
||||||
if (value instanceof JSONArray) { |
|
||||||
ja = (JSONArray)value; |
|
||||||
length = ja.length(); |
|
||||||
for (i = 0; i < length; i += 1) { |
|
||||||
if (i > 0) { |
|
||||||
sb.append('\n'); |
|
||||||
} |
|
||||||
sb.append(escape(ja.get(i).toString())); |
|
||||||
} |
|
||||||
} else { |
|
||||||
sb.append(escape(value.toString())); |
|
||||||
} |
|
||||||
|
|
||||||
// Emit an array of similar keys
|
|
||||||
|
|
||||||
} else if (value instanceof JSONArray) { |
|
||||||
ja = (JSONArray)value; |
|
||||||
length = ja.length(); |
|
||||||
for (i = 0; i < length; i += 1) { |
|
||||||
value = ja.get(i); |
|
||||||
if (value instanceof JSONArray) { |
|
||||||
sb.append('<'); |
|
||||||
sb.append(key); |
|
||||||
sb.append('>'); |
|
||||||
sb.append(toString(value)); |
|
||||||
sb.append("</"); |
|
||||||
sb.append(key); |
|
||||||
sb.append('>'); |
|
||||||
} else { |
|
||||||
sb.append(toString(value, 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(); |
|
||||||
|
|
||||||
// XML does not have good support for arrays. If an array appears in a place
|
|
||||||
// where XML is lacking, synthesize an <array> element.
|
|
||||||
|
|
||||||
} else { |
|
||||||
if (object.getClass().isArray()) { |
|
||||||
object = new JSONArray(object); |
|
||||||
} |
|
||||||
if (object instanceof JSONArray) { |
|
||||||
ja = (JSONArray)object; |
|
||||||
length = ja.length(); |
|
||||||
for (i = 0; i < length; i += 1) { |
|
||||||
sb.append(toString(ja.opt(i), tagName == null ? "array" : tagName)); |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} else { |
|
||||||
string = (object == null) ? "null" : escape(object.toString()); |
|
||||||
return (tagName == null) ? "\"" + string + "\"" : |
|
||||||
(string.length() == 0) ? "<" + tagName + "/>" : |
|
||||||
"<" + tagName + ">" + string + "</" + tagName + ">"; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,365 +0,0 @@ |
|||||||
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 2010-12-24 |
|
||||||
*/ |
|
||||||
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 entity; |
|
||||||
|
|
||||||
static { |
|
||||||
entity = new java.util.HashMap(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; |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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; |
|
||||||
StringBuffer sb; |
|
||||||
do { |
|
||||||
c = next(); |
|
||||||
} while (Character.isWhitespace(c)); |
|
||||||
if (c == 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
if (c == '<') { |
|
||||||
return XML.LT; |
|
||||||
} |
|
||||||
sb = new StringBuffer(); |
|
||||||
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 { |
|
||||||
StringBuffer sb = new StringBuffer(); |
|
||||||
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; |
|
||||||
StringBuffer 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 StringBuffer(); |
|
||||||
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 StringBuffer(); |
|
||||||
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; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,45 +0,0 @@ |
|||||||
/* |
|
||||||
This file is part of Libresonic. |
|
||||||
|
|
||||||
Libresonic is free software: you can redistribute it and/or modify |
|
||||||
it under the terms of the GNU General Public License as published by |
|
||||||
the Free Software Foundation, either version 3 of the License, or |
|
||||||
(at your option) any later version. |
|
||||||
|
|
||||||
Libresonic is distributed in the hope that it will be useful, |
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
GNU General Public License for more details. |
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License |
|
||||||
along with Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Copyright 2016 (C) Libresonic Authors |
|
||||||
Based upon Subsonic, Copyright 2009 (C) Sindre Mehus |
|
||||||
*/ |
|
||||||
package org.libresonic.player.service; |
|
||||||
|
|
||||||
/** |
|
||||||
* Provides services for generating ads. |
|
||||||
* |
|
||||||
* @author Sindre Mehus |
|
||||||
*/ |
|
||||||
public class AdService { |
|
||||||
|
|
||||||
private int adInterval; |
|
||||||
private int pageCount; |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns whether an ad should be displayed. |
|
||||||
*/ |
|
||||||
public boolean showAd() { |
|
||||||
return pageCount++ % adInterval == 0; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set by Spring. |
|
||||||
*/ |
|
||||||
public void setAdInterval(int adInterval) { |
|
||||||
this.adInterval = adInterval; |
|
||||||
} |
|
||||||
} |
|
@ -1,49 +0,0 @@ |
|||||||
/** |
|
||||||
* This file is part of Libresonic. |
|
||||||
* |
|
||||||
* Libresonic is free software: you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation, either version 3 of the License, or |
|
||||||
* (at your option) any later version. |
|
||||||
* |
|
||||||
* Libresonic is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
* |
|
||||||
* Copyright 2014 (C) Sindre Mehus |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.libresonic.player.service; |
|
||||||
|
|
||||||
import de.umass.lastfm.cache.ExpirationPolicy; |
|
||||||
|
|
||||||
import java.util.LinkedHashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* Artist and album info is cached permanently. Everything else is cached one year. |
|
||||||
* |
|
||||||
* @author Sindre Mehus |
|
||||||
* @version $Id$ |
|
||||||
*/ |
|
||||||
public class LastFmExpirationPolicy implements ExpirationPolicy { |
|
||||||
|
|
||||||
private final static long ONE_YEAR = 12 * 30 * 24 * 3600 * 1000L; |
|
||||||
|
|
||||||
private final Map<String, Long> methodToExpirationTime = new LinkedHashMap<String, Long>() {{ |
|
||||||
put("artist.getInfo", Long.MAX_VALUE); // Cache forever
|
|
||||||
put("album.getInfo", Long.MAX_VALUE); // Cache forever
|
|
||||||
put("album.search", -1L); // Don't cache
|
|
||||||
}}; |
|
||||||
|
|
||||||
@Override |
|
||||||
public long getExpirationTime(String method, Map<String, String> params) { |
|
||||||
Long expirationTime = methodToExpirationTime.get(method); |
|
||||||
return expirationTime == null ? ONE_YEAR : expirationTime; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -1,143 +0,0 @@ |
|||||||
/* |
|
||||||
This file is part of Libresonic. |
|
||||||
|
|
||||||
Libresonic is free software: you can redistribute it and/or modify |
|
||||||
it under the terms of the GNU General Public License as published by |
|
||||||
the Free Software Foundation, either version 3 of the License, or |
|
||||||
(at your option) any later version. |
|
||||||
|
|
||||||
Libresonic is distributed in the hope that it will be useful, |
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
GNU General Public License for more details. |
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License |
|
||||||
along with Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Copyright 2016 (C) Libresonic Authors |
|
||||||
Based upon Subsonic, Copyright 2009 (C) Sindre Mehus |
|
||||||
*/ |
|
||||||
package org.libresonic.player.service.upnp; |
|
||||||
|
|
||||||
import org.fourthline.cling.UpnpService; |
|
||||||
import org.fourthline.cling.model.action.ActionInvocation; |
|
||||||
import org.fourthline.cling.model.message.UpnpResponse; |
|
||||||
import org.fourthline.cling.model.meta.Device; |
|
||||||
import org.fourthline.cling.model.meta.Service; |
|
||||||
import org.fourthline.cling.support.igd.PortMappingListener; |
|
||||||
import org.fourthline.cling.support.igd.callback.PortMappingAdd; |
|
||||||
import org.fourthline.cling.support.igd.callback.PortMappingDelete; |
|
||||||
import org.fourthline.cling.support.model.PortMapping; |
|
||||||
import org.libresonic.player.service.UPnPService; |
|
||||||
|
|
||||||
import java.net.InetAddress; |
|
||||||
import java.net.UnknownHostException; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.concurrent.Semaphore; |
|
||||||
import java.util.concurrent.atomic.AtomicReference; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Sindre Mehus |
|
||||||
* @version $Id$ |
|
||||||
*/ |
|
||||||
public class ClingRouter implements Router { |
|
||||||
|
|
||||||
private final Service connectionService; |
|
||||||
private final UpnpService upnpService; |
|
||||||
|
|
||||||
public static ClingRouter findRouter(UPnPService upnpService) { |
|
||||||
final Service connectionService = findConnectionService(upnpService.getUpnpService()); |
|
||||||
if (connectionService == null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return new ClingRouter(connectionService, upnpService.getUpnpService()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the UPnP service used for port mapping. |
|
||||||
*/ |
|
||||||
private static Service findConnectionService(UpnpService upnpService) { |
|
||||||
|
|
||||||
class ConnectionServiceDiscoverer extends PortMappingListener { |
|
||||||
ConnectionServiceDiscoverer() { |
|
||||||
super(new PortMapping[0]); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Service discoverConnectionService(Device device) { |
|
||||||
return super.discoverConnectionService(device); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ConnectionServiceDiscoverer discoverer = new ConnectionServiceDiscoverer(); |
|
||||||
Collection<Device> devices = upnpService.getRegistry().getDevices(); |
|
||||||
for (Device device : devices) { |
|
||||||
Service service = discoverer.discoverConnectionService(device); |
|
||||||
if (service != null) { |
|
||||||
return service; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public ClingRouter(Service connectionService, UpnpService upnpService) { |
|
||||||
this.connectionService = connectionService; |
|
||||||
this.upnpService = upnpService; |
|
||||||
} |
|
||||||
|
|
||||||
public void addPortMapping(int externalPort, int internalPort, int leaseDuration) throws Exception { |
|
||||||
addPortMappingImpl(connectionService, internalPort); |
|
||||||
} |
|
||||||
|
|
||||||
public void deletePortMapping(int externalPort, int internalPort) throws Exception { |
|
||||||
deletePortMappingImpl(connectionService, internalPort); |
|
||||||
} |
|
||||||
|
|
||||||
private void addPortMappingImpl(Service connectionService, int port) throws Exception { |
|
||||||
final Semaphore gotReply = new Semaphore(0); |
|
||||||
final AtomicReference<String> error = new AtomicReference<String>(); |
|
||||||
upnpService.getControlPoint().execute( |
|
||||||
new PortMappingAdd(connectionService, createPortMapping(port)) { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void success(ActionInvocation invocation) { |
|
||||||
gotReply.release(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void failure(ActionInvocation invocation, UpnpResponse response, String defaultMsg) { |
|
||||||
error.set(String.valueOf(response) + ": " + defaultMsg); |
|
||||||
gotReply.release(); |
|
||||||
} |
|
||||||
} |
|
||||||
); |
|
||||||
gotReply.acquire(); |
|
||||||
if (error.get() != null) { |
|
||||||
throw new Exception(error.get()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void deletePortMappingImpl(Service connectionService, int port) throws Exception { |
|
||||||
final Semaphore gotReply = new Semaphore(0); |
|
||||||
upnpService.getControlPoint().execute( |
|
||||||
new PortMappingDelete(connectionService, createPortMapping(port)) { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void success(ActionInvocation invocation) { |
|
||||||
gotReply.release(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void failure(ActionInvocation invocation, UpnpResponse response, String defaultMsg) { |
|
||||||
gotReply.release(); |
|
||||||
} |
|
||||||
} |
|
||||||
); |
|
||||||
gotReply.acquire(); |
|
||||||
} |
|
||||||
|
|
||||||
private PortMapping createPortMapping(int port) throws UnknownHostException { |
|
||||||
String localIp = InetAddress.getLocalHost().getHostAddress(); |
|
||||||
return new PortMapping(port, localIp, PortMapping.Protocol.TCP, "Libresonic"); |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue