33 | * Each row of text represents a row in a table or a data record. Each row 34 | * ends with a NEWLINE character. Each row contains one or more values. 35 | * Values are separated by commas. A value can contain any character except 36 | * for comma, unless is is wrapped in single quotes or double quotes. 37 | *
38 | * The first row usually contains the names of the columns. 39 | *
40 | * A comma delimited list can be converted into a JSONArray of JSONObjects.
41 | * The names for the elements in the JSONObjects can be taken from the names
42 | * in the first row.
43 | * @author JSON.org
44 | * @version 2016-05-01
45 | */
46 | public class CDL {
47 |
48 | /**
49 | * Get the next value. The value can be wrapped in quotes. The value can
50 | * be empty.
51 | * @param x A JSONTokener of the source text.
52 | * @return The value string, or null if empty.
53 | * @throws JSONException if the quoted string is badly formed.
54 | */
55 | private static String getValue(JSONTokener x) throws JSONException {
56 | char c;
57 | char q;
58 | StringBuffer sb;
59 | do {
60 | c = x.next();
61 | } while (c == ' ' || c == '\t');
62 | switch (c) {
63 | case 0:
64 | return null;
65 | case '"':
66 | case '\'':
67 | q = c;
68 | sb = new StringBuffer();
69 | for (;;) {
70 | c = x.next();
71 | if (c == q) {
72 | //Handle escaped double-quote
73 | if(x.next() != '\"')
74 | {
75 | x.back();
76 | break;
77 | }
78 | }
79 | if (c == 0 || c == '\n' || c == '\r') {
80 | throw x.syntaxError("Missing close quote '" + q + "'.");
81 | }
82 | sb.append(c);
83 | }
84 | return sb.toString();
85 | case ',':
86 | x.back();
87 | return "";
88 | default:
89 | x.back();
90 | return x.nextTo(',');
91 | }
92 | }
93 |
94 | /**
95 | * Produce a JSONArray of strings from a row of comma delimited values.
96 | * @param x A JSONTokener of the source text.
97 | * @return A JSONArray of strings.
98 | * @throws JSONException
99 | */
100 | public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
101 | JSONArray ja = new JSONArray();
102 | for (;;) {
103 | String value = getValue(x);
104 | char c = x.next();
105 | if (value == null ||
106 | (ja.length() == 0 && value.length() == 0 && c != ',')) {
107 | return null;
108 | }
109 | ja.put(value);
110 | for (;;) {
111 | if (c == ',') {
112 | break;
113 | }
114 | if (c != ' ') {
115 | if (c == '\n' || c == '\r' || c == 0) {
116 | return ja;
117 | }
118 | throw x.syntaxError("Bad character '" + c + "' (" +
119 | (int)c + ").");
120 | }
121 | c = x.next();
122 | }
123 | }
124 | }
125 |
126 | /**
127 | * Produce a JSONObject from a row of comma delimited text, using a
128 | * parallel JSONArray of strings to provides the names of the elements.
129 | * @param names A JSONArray of names. This is commonly obtained from the
130 | * first row of a comma delimited text file using the rowToJSONArray
131 | * method.
132 | * @param x A JSONTokener of the source text.
133 | * @return A JSONObject combining the names and values.
134 | * @throws JSONException
135 | */
136 | public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
137 | throws JSONException {
138 | JSONArray ja = rowToJSONArray(x);
139 | return ja != null ? ja.toJSONObject(names) : null;
140 | }
141 |
142 | /**
143 | * Produce a comma delimited text row from a JSONArray. Values containing
144 | * the comma character will be quoted. Troublesome characters may be
145 | * removed.
146 | * @param ja A JSONArray of strings.
147 | * @return A string ending in NEWLINE.
148 | */
149 | public static String rowToString(JSONArray ja) {
150 | StringBuilder sb = new StringBuilder();
151 | for (int i = 0; i < ja.length(); i += 1) {
152 | if (i > 0) {
153 | sb.append(',');
154 | }
155 | Object object = ja.opt(i);
156 | if (object != null) {
157 | String string = object.toString();
158 | if (string.length() > 0 && (string.indexOf(',') >= 0 ||
159 | string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 ||
160 | string.indexOf(0) >= 0 || string.charAt(0) == '"')) {
161 | sb.append('"');
162 | int length = string.length();
163 | for (int j = 0; j < length; j += 1) {
164 | char c = string.charAt(j);
165 | if (c >= ' ' && c != '"') {
166 | sb.append(c);
167 | }
168 | }
169 | sb.append('"');
170 | } else {
171 | sb.append(string);
172 | }
173 | }
174 | }
175 | sb.append('\n');
176 | return sb.toString();
177 | }
178 |
179 | /**
180 | * Produce a JSONArray of JSONObjects from a comma delimited text string,
181 | * using the first row as a source of names.
182 | * @param string The comma delimited text.
183 | * @return A JSONArray of JSONObjects.
184 | * @throws JSONException
185 | */
186 | public static JSONArray toJSONArray(String string) throws JSONException {
187 | return toJSONArray(new JSONTokener(string));
188 | }
189 |
190 | /**
191 | * Produce a JSONArray of JSONObjects from a comma delimited text string,
192 | * using the first row as a source of names.
193 | * @param x The JSONTokener containing the comma delimited text.
194 | * @return A JSONArray of JSONObjects.
195 | * @throws JSONException
196 | */
197 | public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
198 | return toJSONArray(rowToJSONArray(x), x);
199 | }
200 |
201 | /**
202 | * Produce a JSONArray of JSONObjects from a comma delimited text string
203 | * using a supplied JSONArray as the source of element names.
204 | * @param names A JSONArray of strings.
205 | * @param string The comma delimited text.
206 | * @return A JSONArray of JSONObjects.
207 | * @throws JSONException
208 | */
209 | public static JSONArray toJSONArray(JSONArray names, String string)
210 | throws JSONException {
211 | return toJSONArray(names, new JSONTokener(string));
212 | }
213 |
214 | /**
215 | * Produce a JSONArray of JSONObjects from a comma delimited text string
216 | * using a supplied JSONArray as the source of element names.
217 | * @param names A JSONArray of strings.
218 | * @param x A JSONTokener of the source text.
219 | * @return A JSONArray of JSONObjects.
220 | * @throws JSONException
221 | */
222 | public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
223 | throws JSONException {
224 | if (names == null || names.length() == 0) {
225 | return null;
226 | }
227 | JSONArray ja = new JSONArray();
228 | for (;;) {
229 | JSONObject jo = rowToJSONObject(names, x);
230 | if (jo == null) {
231 | break;
232 | }
233 | ja.put(jo);
234 | }
235 | if (ja.length() == 0) {
236 | return null;
237 | }
238 | return ja;
239 | }
240 |
241 |
242 | /**
243 | * Produce a comma delimited text from a JSONArray of JSONObjects. The
244 | * first row will be a list of names obtained by inspecting the first
245 | * JSONObject.
246 | * @param ja A JSONArray of JSONObjects.
247 | * @return A comma delimited text.
248 | * @throws JSONException
249 | */
250 | public static String toString(JSONArray ja) throws JSONException {
251 | JSONObject jo = ja.optJSONObject(0);
252 | if (jo != null) {
253 | JSONArray names = jo.names();
254 | if (names != null) {
255 | return rowToString(names) + toString(names, ja);
256 | }
257 | }
258 | return null;
259 | }
260 |
261 | /**
262 | * Produce a comma delimited text from a JSONArray of JSONObjects using
263 | * a provided list of names. The list of names is not included in the
264 | * output.
265 | * @param names A JSONArray of strings.
266 | * @param ja A JSONArray of JSONObjects.
267 | * @return A comma delimited text.
268 | * @throws JSONException
269 | */
270 | public static String toString(JSONArray names, JSONArray ja)
271 | throws JSONException {
272 | if (names == null || names.length() == 0) {
273 | return null;
274 | }
275 | StringBuffer sb = new StringBuffer();
276 | for (int i = 0; i < ja.length(); i += 1) {
277 | JSONObject jo = ja.optJSONObject(i);
278 | if (jo != null) {
279 | sb.append(rowToString(jo.toJSONArray(names)));
280 | }
281 | }
282 | return sb.toString();
283 | }
284 | }
285 |
--------------------------------------------------------------------------------
/src/org/json/Cookie.java:
--------------------------------------------------------------------------------
1 | package org.json;
2 |
3 | /*
4 | Copyright (c) 2002 JSON.org
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | The Software shall be used for Good, not Evil.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | */
26 |
27 | /**
28 | * Convert a web browser cookie specification to a JSONObject and back.
29 | * JSON and Cookies are both notations for name/value pairs.
30 | * @author JSON.org
31 | * @version 2015-12-09
32 | */
33 | public class Cookie {
34 |
35 | /**
36 | * Produce a copy of a string in which the characters '+', '%', '=', ';'
37 | * and control characters are replaced with "%hh". This is a gentle form
38 | * of URL encoding, attempting to cause as little distortion to the
39 | * string as possible. The characters '=' and ';' are meta characters in
40 | * cookies. By convention, they are escaped using the URL-encoding. This is
41 | * only a convention, not a standard. Often, cookies are expected to have
42 | * encoded values. We encode '=' and ';' because we must. We encode '%' and
43 | * '+' because they are meta characters in URL encoding.
44 | * @param string The source string.
45 | * @return The escaped result.
46 | */
47 | public static String escape(String string) {
48 | char c;
49 | String s = string.trim();
50 | int length = s.length();
51 | StringBuilder sb = new StringBuilder(length);
52 | for (int i = 0; i < length; i += 1) {
53 | c = s.charAt(i);
54 | if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') {
55 | sb.append('%');
56 | sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16));
57 | sb.append(Character.forDigit((char)(c & 0x0f), 16));
58 | } else {
59 | sb.append(c);
60 | }
61 | }
62 | return sb.toString();
63 | }
64 |
65 |
66 | /**
67 | * Convert a cookie specification string into a JSONObject. The string
68 | * will contain a name value pair separated by '='. The name and the value
69 | * will be unescaped, possibly converting '+' and '%' sequences. The
70 | * cookie properties may follow, separated by ';', also represented as
71 | * name=value (except the secure property, which does not have a value).
72 | * The name will be stored under the key "name", and the value will be
73 | * stored under the key "value". This method does not do checking or
74 | * validation of the parameters. It only converts the cookie string into
75 | * a JSONObject.
76 | * @param string The cookie specification string.
77 | * @return A JSONObject containing "name", "value", and possibly other
78 | * members.
79 | * @throws JSONException
80 | */
81 | public static JSONObject toJSONObject(String string) throws JSONException {
82 | String name;
83 | JSONObject jo = new JSONObject();
84 | Object value;
85 | JSONTokener x = new JSONTokener(string);
86 | jo.put("name", x.nextTo('='));
87 | x.next('=');
88 | jo.put("value", x.nextTo(';'));
89 | x.next();
90 | while (x.more()) {
91 | name = unescape(x.nextTo("=;"));
92 | if (x.next() != '=') {
93 | if (name.equals("secure")) {
94 | value = Boolean.TRUE;
95 | } else {
96 | throw x.syntaxError("Missing '=' in cookie parameter.");
97 | }
98 | } else {
99 | value = unescape(x.nextTo(';'));
100 | x.next();
101 | }
102 | jo.put(name, value);
103 | }
104 | return jo;
105 | }
106 |
107 |
108 | /**
109 | * Convert a JSONObject into a cookie specification string. The JSONObject
110 | * must contain "name" and "value" members.
111 | * If the JSONObject contains "expires", "domain", "path", or "secure"
112 | * members, they will be appended to the cookie specification string.
113 | * All other members are ignored.
114 | * @param jo A JSONObject
115 | * @return A cookie specification string
116 | * @throws JSONException
117 | */
118 | public static String toString(JSONObject jo) throws JSONException {
119 | StringBuilder sb = new StringBuilder();
120 |
121 | sb.append(escape(jo.getString("name")));
122 | sb.append("=");
123 | sb.append(escape(jo.getString("value")));
124 | if (jo.has("expires")) {
125 | sb.append(";expires=");
126 | sb.append(jo.getString("expires"));
127 | }
128 | if (jo.has("domain")) {
129 | sb.append(";domain=");
130 | sb.append(escape(jo.getString("domain")));
131 | }
132 | if (jo.has("path")) {
133 | sb.append(";path=");
134 | sb.append(escape(jo.getString("path")));
135 | }
136 | if (jo.optBoolean("secure")) {
137 | sb.append(";secure");
138 | }
139 | return sb.toString();
140 | }
141 |
142 | /**
143 | * Convert
35 | * A JSONStringer instance provides a
51 | * The first method called must be
55 | * This can sometimes be easier than using a JSONObject to build a string.
56 | * @author JSON.org
57 | * @version 2015-12-09
58 | */
59 | public class JSONStringer extends JSONWriter {
60 | /**
61 | * Make a fresh JSONStringer. It can be used to build one JSON text.
62 | */
63 | public JSONStringer() {
64 | super(new StringWriter());
65 | }
66 |
67 | /**
68 | * Return the JSON text. This method is used to obtain the product of the
69 | * JSONStringer instance. It will return
36 | * A JSONWriter instance provides a
51 | * The first method called must be
55 | * This can sometimes be easier than using a JSONObject to build a string.
56 | * @author JSON.org
57 | * @version 2015-12-09
58 | */
59 | public class JSONWriter {
60 | private static final int maxdepth = 200;
61 |
62 | /**
63 | * The comma flag determines if a comma should be output before the next
64 | * value.
65 | */
66 | private boolean comma;
67 |
68 | /**
69 | * The current mode. Values:
70 | * 'a' (array),
71 | * 'd' (done),
72 | * 'i' (initial),
73 | * 'k' (key),
74 | * 'o' (object).
75 | */
76 | protected char mode;
77 |
78 | /**
79 | * The object/array stack.
80 | */
81 | private final JSONObject stack[];
82 |
83 | /**
84 | * The stack top index. A value of 0 indicates that the stack is empty.
85 | */
86 | private int top;
87 |
88 | /**
89 | * The writer that will receive the output.
90 | */
91 | protected Writer writer;
92 |
93 | /**
94 | * Make a fresh JSONWriter. It can be used to build one JSON text.
95 | */
96 | public JSONWriter(Writer w) {
97 | this.comma = false;
98 | this.mode = 'i';
99 | this.stack = new JSONObject[maxdepth];
100 | this.top = 0;
101 | this.writer = w;
102 | }
103 |
104 | /**
105 | * Append a value.
106 | * @param string A string value.
107 | * @return this
108 | * @throws JSONException If the value is out of sequence.
109 | */
110 | private JSONWriter append(String string) throws JSONException {
111 | if (string == null) {
112 | throw new JSONException("Null pointer");
113 | }
114 | if (this.mode == 'o' || this.mode == 'a') {
115 | try {
116 | if (this.comma && this.mode == 'a') {
117 | this.writer.write(',');
118 | }
119 | this.writer.write(string);
120 | } catch (IOException e) {
121 | throw new JSONException(e);
122 | }
123 | if (this.mode == 'o') {
124 | this.mode = 'k';
125 | }
126 | this.comma = true;
127 | return this;
128 | }
129 | throw new JSONException("Value out of sequence.");
130 | }
131 |
132 | /**
133 | * Begin appending a new array. All values until the balancing
134 | * %
hh sequences to single characters, and
144 | * convert plus to space.
145 | * @param string A string that may contain
146 | * +
(plus) and
147 | * %
hh sequences.
148 | * @return The unescaped string.
149 | */
150 | public static String unescape(String string) {
151 | int length = string.length();
152 | StringBuilder sb = new StringBuilder(length);
153 | for (int i = 0; i < length; ++i) {
154 | char c = string.charAt(i);
155 | if (c == '+') {
156 | c = ' ';
157 | } else if (c == '%' && i + 2 < length) {
158 | int d = JSONTokener.dehexchar(string.charAt(i + 1));
159 | int e = JSONTokener.dehexchar(string.charAt(i + 2));
160 | if (d >= 0 && e >= 0) {
161 | c = (char)(d * 16 + e);
162 | i += 2;
163 | }
164 | }
165 | sb.append(c);
166 | }
167 | return sb.toString();
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/org/json/CookieList.java:
--------------------------------------------------------------------------------
1 | package org.json;
2 |
3 | /*
4 | Copyright (c) 2002 JSON.org
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | The Software shall be used for Good, not Evil.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | */
26 |
27 | import java.util.Iterator;
28 |
29 | /**
30 | * Convert a web browser cookie list string to a JSONObject and back.
31 | * @author JSON.org
32 | * @version 2015-12-09
33 | */
34 | public class CookieList {
35 |
36 | /**
37 | * Convert a cookie list into a JSONObject. A cookie list is a sequence
38 | * of name/value pairs. The names are separated from the values by '='.
39 | * The pairs are separated by ';'. The names and the values
40 | * will be unescaped, possibly converting '+' and '%' sequences.
41 | *
42 | * To add a cookie to a cooklist,
43 | * cookielistJSONObject.put(cookieJSONObject.getString("name"),
44 | * cookieJSONObject.getString("value"));
45 | * @param string A cookie list string
46 | * @return A JSONObject
47 | * @throws JSONException
48 | */
49 | public static JSONObject toJSONObject(String string) throws JSONException {
50 | JSONObject jo = new JSONObject();
51 | JSONTokener x = new JSONTokener(string);
52 | while (x.more()) {
53 | String name = Cookie.unescape(x.nextTo('='));
54 | x.next('=');
55 | jo.put(name, Cookie.unescape(x.nextTo(';')));
56 | x.next();
57 | }
58 | return jo;
59 | }
60 |
61 | /**
62 | * Convert a JSONObject into a cookie list. A cookie list is a sequence
63 | * of name/value pairs. The names are separated from the values by '='.
64 | * The pairs are separated by ';'. The characters '%', '+', '=', and ';'
65 | * in the names and values are replaced by "%hh".
66 | * @param jo A JSONObject
67 | * @return A cookie list string
68 | * @throws JSONException
69 | */
70 | public static String toString(JSONObject jo) throws JSONException {
71 | boolean b = false;
72 | Iterator{
43 | * Method: "POST" (for example),
44 | * "Request-URI": "/" (for example),
45 | * "HTTP-Version": "HTTP/1.1" (for example)
46 | * }
47 | * A response header will contain
48 | * {
49 | * "HTTP-Version": "HTTP/1.1" (for example),
50 | * "Status-Code": "200" (for example),
51 | * "Reason-Phrase": "OK" (for example)
52 | * }
53 | * In addition, the other parameters in the header will be captured, using
54 | * the HTTP field names as JSON names, so that
55 | * Date: Sun, 26 May 2002 18:06:04 GMT
56 | * Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
57 | * Cache-Control: no-cache
58 | * become
59 | * {...
60 | * Date: "Sun, 26 May 2002 18:06:04 GMT",
61 | * Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
62 | * "Cache-Control": "no-cache",
63 | * ...}
64 | * It does no further checking or conversion. It does not parse dates.
65 | * It does not do '%' transforms on URLs.
66 | * @param string An HTTP header string.
67 | * @return A JSONObject containing the elements and attributes
68 | * of the XML string.
69 | * @throws JSONException
70 | */
71 | public static JSONObject toJSONObject(String string) throws JSONException {
72 | JSONObject jo = new JSONObject();
73 | HTTPTokener x = new HTTPTokener(string);
74 | String token;
75 |
76 | token = x.nextToken();
77 | if (token.toUpperCase().startsWith("HTTP")) {
78 |
79 | // Response
80 |
81 | jo.put("HTTP-Version", token);
82 | jo.put("Status-Code", x.nextToken());
83 | jo.put("Reason-Phrase", x.nextTo('\0'));
84 | x.next();
85 |
86 | } else {
87 |
88 | // Request
89 |
90 | jo.put("Method", token);
91 | jo.put("Request-URI", x.nextToken());
92 | jo.put("HTTP-Version", x.nextToken());
93 | }
94 |
95 | // Fields
96 |
97 | while (x.more()) {
98 | String name = x.nextTo(':');
99 | x.next(':');
100 | jo.put(name, x.nextTo('\0'));
101 | x.next();
102 | }
103 | return jo;
104 | }
105 |
106 |
107 | /**
108 | * Convert a JSONObject into an HTTP header. A request header must contain
109 | * {
110 | * Method: "POST" (for example),
111 | * "Request-URI": "/" (for example),
112 | * "HTTP-Version": "HTTP/1.1" (for example)
113 | * }
114 | * A response header must contain
115 | * {
116 | * "HTTP-Version": "HTTP/1.1" (for example),
117 | * "Status-Code": "200" (for example),
118 | * "Reason-Phrase": "OK" (for example)
119 | * }
120 | * Any other members of the JSONObject will be output as HTTP fields.
121 | * The result will end with two CRLF pairs.
122 | * @param jo A JSONObject
123 | * @return An HTTP header string.
124 | * @throws JSONException if the object does not contain enough
125 | * information.
126 | */
127 | public static String toString(JSONObject jo) throws JSONException {
128 | Iterator<[ [ ]]>
are ignored.
245 | * @param string The source string.
246 | * @return A JSONArray containing the structured data from the XML string.
247 | * @throws JSONException Thrown on error converting to a JSONArray
248 | */
249 | public static JSONArray toJSONArray(String string) throws JSONException {
250 | return (JSONArray)parse(new XMLTokener(string), true, null, false);
251 | }
252 |
253 |
254 | /**
255 | * Convert a well-formed (but not necessarily valid) XML string into a
256 | * JSONArray using the JsonML transform. Each XML tag is represented as
257 | * a JSONArray in which the first element is the tag name. If the tag has
258 | * attributes, then the second element will be JSONObject containing the
259 | * name/value pairs. If the tag contains children, then strings and
260 | * JSONArrays will represent the child tags.
261 | * As opposed to toJSONArray this method does not attempt to convert
262 | * any text node or attribute value to any type
263 | * but just leaves it as a string.
264 | * Comments, prologs, DTDs, and <[ [ ]]>
are ignored.
265 | * @param string The source string.
266 | * @param keepStrings If true, then values will not be coerced into boolean
267 | * or numeric values and will instead be left as strings
268 | * @return A JSONArray containing the structured data from the XML string.
269 | * @throws JSONException Thrown on error converting to a JSONArray
270 | */
271 | public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException {
272 | return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings);
273 | }
274 |
275 |
276 | /**
277 | * Convert a well-formed (but not necessarily valid) XML string into a
278 | * JSONArray using the JsonML transform. Each XML tag is represented as
279 | * a JSONArray in which the first element is the tag name. If the tag has
280 | * attributes, then the second element will be JSONObject containing the
281 | * name/value pairs. If the tag contains children, then strings and
282 | * JSONArrays will represent the child content and tags.
283 | * As opposed to toJSONArray this method does not attempt to convert
284 | * any text node or attribute value to any type
285 | * but just leaves it as a string.
286 | * Comments, prologs, DTDs, and <[ [ ]]>
are ignored.
287 | * @param x An XMLTokener.
288 | * @param keepStrings If true, then values will not be coerced into boolean
289 | * or numeric values and will instead be left as strings
290 | * @return A JSONArray containing the structured data from the XML string.
291 | * @throws JSONException Thrown on error converting to a JSONArray
292 | */
293 | public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException {
294 | return (JSONArray)parse(x, true, null, keepStrings);
295 | }
296 |
297 |
298 | /**
299 | * Convert a well-formed (but not necessarily valid) XML string into a
300 | * JSONArray using the JsonML transform. Each XML tag is represented as
301 | * a JSONArray in which the first element is the tag name. If the tag has
302 | * attributes, then the second element will be JSONObject containing the
303 | * name/value pairs. If the tag contains children, then strings and
304 | * JSONArrays will represent the child content and tags.
305 | * Comments, prologs, DTDs, and <[ [ ]]>
are ignored.
306 | * @param x An XMLTokener.
307 | * @return A JSONArray containing the structured data from the XML string.
308 | * @throws JSONException Thrown on error converting to a JSONArray
309 | */
310 | public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
311 | return (JSONArray)parse(x, true, null, false);
312 | }
313 |
314 |
315 | /**
316 | * Convert a well-formed (but not necessarily valid) XML string into a
317 | * JSONObject using the JsonML transform. Each XML tag is represented as
318 | * a JSONObject with a "tagName" property. If the tag has attributes, then
319 | * the attributes will be in the JSONObject as properties. If the tag
320 | * contains children, the object will have a "childNodes" property which
321 | * will be an array of strings and JsonML JSONObjects.
322 |
323 | * Comments, prologs, DTDs, and <[ [ ]]>
are ignored.
324 | * @param string The XML source text.
325 | * @return A JSONObject containing the structured data from the XML string.
326 | * @throws JSONException Thrown on error converting to a JSONObject
327 | */
328 | public static JSONObject toJSONObject(String string) throws JSONException {
329 | return (JSONObject)parse(new XMLTokener(string), false, null, false);
330 | }
331 |
332 |
333 | /**
334 | * Convert a well-formed (but not necessarily valid) XML string into a
335 | * JSONObject using the JsonML transform. Each XML tag is represented as
336 | * a JSONObject with a "tagName" property. If the tag has attributes, then
337 | * the attributes will be in the JSONObject as properties. If the tag
338 | * contains children, the object will have a "childNodes" property which
339 | * will be an array of strings and JsonML JSONObjects.
340 |
341 | * Comments, prologs, DTDs, and <[ [ ]]>
are ignored.
342 | * @param string The XML source text.
343 | * @param keepStrings If true, then values will not be coerced into boolean
344 | * or numeric values and will instead be left as strings
345 | * @return A JSONObject containing the structured data from the XML string.
346 | * @throws JSONException Thrown on error converting to a JSONObject
347 | */
348 | public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
349 | return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings);
350 | }
351 |
352 |
353 | /**
354 | * Convert a well-formed (but not necessarily valid) XML string into a
355 | * JSONObject using the JsonML transform. Each XML tag is represented as
356 | * a JSONObject with a "tagName" property. If the tag has attributes, then
357 | * the attributes will be in the JSONObject as properties. If the tag
358 | * contains children, the object will have a "childNodes" property which
359 | * will be an array of strings and JsonML JSONObjects.
360 |
361 | * Comments, prologs, DTDs, and <[ [ ]]>
are ignored.
362 | * @param x An XMLTokener of the XML source text.
363 | * @return A JSONObject containing the structured data from the XML string.
364 | * @throws JSONException Thrown on error converting to a JSONObject
365 | */
366 | public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
367 | return (JSONObject)parse(x, false, null, false);
368 | }
369 |
370 |
371 | /**
372 | * Convert a well-formed (but not necessarily valid) XML string into a
373 | * JSONObject using the JsonML transform. Each XML tag is represented as
374 | * a JSONObject with a "tagName" property. If the tag has attributes, then
375 | * the attributes will be in the JSONObject as properties. If the tag
376 | * contains children, the object will have a "childNodes" property which
377 | * will be an array of strings and JsonML JSONObjects.
378 |
379 | * Comments, prologs, DTDs, and <[ [ ]]>
are ignored.
380 | * @param x An XMLTokener of the XML source text.
381 | * @param keepStrings If true, then values will not be coerced into boolean
382 | * or numeric values and will instead be left as strings
383 | * @return A JSONObject containing the structured data from the XML string.
384 | * @throws JSONException Thrown on error converting to a JSONObject
385 | */
386 | public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException {
387 | return (JSONObject)parse(x, false, null, keepStrings);
388 | }
389 |
390 |
391 | /**
392 | * Reverse the JSONML transformation, making an XML text from a JSONArray.
393 | * @param ja A JSONArray.
394 | * @return An XML string.
395 | * @throws JSONException Thrown on error converting to a string
396 | */
397 | public static String toString(JSONArray ja) throws JSONException {
398 | int i;
399 | JSONObject jo;
400 | String key;
401 | Iterator
118 | *
119 | * @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained
120 | * {@link Builder#append(String)} calls.
121 | */
122 | public static Builder builder() {
123 | return new Builder();
124 | }
125 |
126 | // Segments for the JSONPointer string
127 | private final List
111 | * JSONPointer pointer = JSONPointer.builder()
112 | * .append("obj")
113 | * .append("other~key").append("another/key")
114 | * .append("\"")
115 | * .append(0)
116 | * .build();
117 | *
JSONString
interface allows a toJSONString()
4 | * method so that a class can change the behavior of
5 | * JSONObject.toString()
, JSONArray.toString()
,
6 | * and JSONWriter.value(
Object)
. The
7 | * toJSONString
method will be used instead of the default behavior
8 | * of using the Object's toString()
method and quoting the result.
9 | */
10 | public interface JSONString {
11 | /**
12 | * The toJSONString
method allows a class to produce its own JSON
13 | * serialization.
14 | *
15 | * @return A strictly syntactically correct JSON text.
16 | */
17 | public String toJSONString();
18 | }
19 |
--------------------------------------------------------------------------------
/src/org/json/JSONStringer.java:
--------------------------------------------------------------------------------
1 | package org.json;
2 |
3 | /*
4 | Copyright (c) 2006 JSON.org
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | The Software shall be used for Good, not Evil.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | */
26 |
27 | import java.io.StringWriter;
28 |
29 | /**
30 | * JSONStringer provides a quick and convenient way of producing JSON text.
31 | * The texts produced strictly conform to JSON syntax rules. No whitespace is
32 | * added, so the results are ready for transmission or storage. Each instance of
33 | * JSONStringer can produce one JSON text.
34 | * value
method for appending
36 | * values to the
37 | * text, and a key
38 | * method for adding keys before values in objects. There are array
39 | * and endArray
methods that make and bound array values, and
40 | * object
and endObject
methods which make and bound
41 | * object values. All of these methods return the JSONWriter instance,
42 | * permitting cascade style. For example,
43 | * myString = new JSONStringer()
44 | * .object()
45 | * .key("JSON")
46 | * .value("Hello, World!")
47 | * .endObject()
48 | * .toString();
which produces the string
49 | * {"JSON":"Hello, World!"}
50 | * array
or object
.
52 | * There are no methods for adding commas or colons. JSONStringer adds them for
53 | * you. Objects and arrays can be nested up to 20 levels deep.
54 | * null
if there was a
70 | * problem in the construction of the JSON text (such as the calls to
71 | * array
were not properly balanced with calls to
72 | * endArray
).
73 | * @return The JSON text.
74 | */
75 | public String toString() {
76 | return this.mode == 'd' ? this.writer.toString() : null;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/org/json/JSONTokener.java:
--------------------------------------------------------------------------------
1 | package org.json;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.InputStreamReader;
7 | import java.io.Reader;
8 | import java.io.StringReader;
9 |
10 | /*
11 | Copyright (c) 2002 JSON.org
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in all
21 | copies or substantial portions of the Software.
22 |
23 | The Software shall be used for Good, not Evil.
24 |
25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 | SOFTWARE.
32 | */
33 |
34 | /**
35 | * A JSONTokener takes a source string and extracts characters and tokens from
36 | * it. It is used by the JSONObject and JSONArray constructors to parse
37 | * JSON source strings.
38 | * @author JSON.org
39 | * @version 2014-05-03
40 | */
41 | public class JSONTokener {
42 |
43 | private long character;
44 | private boolean eof;
45 | private long index;
46 | private long line;
47 | private char previous;
48 | private Reader reader;
49 | private boolean usePrevious;
50 |
51 |
52 | /**
53 | * Construct a JSONTokener from a Reader.
54 | *
55 | * @param reader A reader.
56 | */
57 | public JSONTokener(Reader reader) {
58 | this.reader = reader.markSupported()
59 | ? reader
60 | : new BufferedReader(reader);
61 | this.eof = false;
62 | this.usePrevious = false;
63 | this.previous = 0;
64 | this.index = 0;
65 | this.character = 1;
66 | this.line = 1;
67 | }
68 |
69 |
70 | /**
71 | * Construct a JSONTokener from an InputStream.
72 | * @param inputStream The source.
73 | */
74 | public JSONTokener(InputStream inputStream) {
75 | this(new InputStreamReader(inputStream));
76 | }
77 |
78 |
79 | /**
80 | * Construct a JSONTokener from a string.
81 | *
82 | * @param s A source string.
83 | */
84 | public JSONTokener(String s) {
85 | this(new StringReader(s));
86 | }
87 |
88 |
89 | /**
90 | * Back up one character. This provides a sort of lookahead capability,
91 | * so that you can test for a digit or letter before attempting to parse
92 | * the next number or identifier.
93 | * @throws JSONException Thrown if trying to step back more than 1 step
94 | * or if already at the start of the string
95 | */
96 | public void back() throws JSONException {
97 | if (this.usePrevious || this.index <= 0) {
98 | throw new JSONException("Stepping back two steps is not supported");
99 | }
100 | this.index -= 1;
101 | this.character -= 1;
102 | this.usePrevious = true;
103 | this.eof = false;
104 | }
105 |
106 |
107 | /**
108 | * Get the hex value of a character (base16).
109 | * @param c A character between '0' and '9' or between 'A' and 'F' or
110 | * between 'a' and 'f'.
111 | * @return An int between 0 and 15, or -1 if c was not a hex digit.
112 | */
113 | public static int dehexchar(char c) {
114 | if (c >= '0' && c <= '9') {
115 | return c - '0';
116 | }
117 | if (c >= 'A' && c <= 'F') {
118 | return c - ('A' - 10);
119 | }
120 | if (c >= 'a' && c <= 'f') {
121 | return c - ('a' - 10);
122 | }
123 | return -1;
124 | }
125 |
126 | /**
127 | * @return true if at the end of the file and we didn't step back
128 | */
129 | public boolean end() {
130 | return this.eof && !this.usePrevious;
131 | }
132 |
133 |
134 | /**
135 | * Determine if the source string still contains characters that next()
136 | * can consume.
137 | * @return true if not yet at the end of the source.
138 | * @throws JSONException thrown if there is an error stepping forward
139 | * or backward while checking for more data.
140 | */
141 | public boolean more() throws JSONException {
142 | this.next();
143 | if (this.end()) {
144 | return false;
145 | }
146 | this.back();
147 | return true;
148 | }
149 |
150 |
151 | /**
152 | * Get the next character in the source string.
153 | *
154 | * @return The next character, or 0 if past the end of the source string.
155 | * @throws JSONException Thrown if there is an error reading the source string.
156 | */
157 | public char next() throws JSONException {
158 | int c;
159 | if (this.usePrevious) {
160 | this.usePrevious = false;
161 | c = this.previous;
162 | } else {
163 | try {
164 | c = this.reader.read();
165 | } catch (IOException exception) {
166 | throw new JSONException(exception);
167 | }
168 |
169 | if (c <= 0) { // End of stream
170 | this.eof = true;
171 | c = 0;
172 | }
173 | }
174 | this.index += 1;
175 | if (this.previous == '\r') {
176 | this.line += 1;
177 | this.character = c == '\n' ? 0 : 1;
178 | } else if (c == '\n') {
179 | this.line += 1;
180 | this.character = 0;
181 | } else {
182 | this.character += 1;
183 | }
184 | this.previous = (char) c;
185 | return this.previous;
186 | }
187 |
188 |
189 | /**
190 | * Consume the next character, and check that it matches a specified
191 | * character.
192 | * @param c The character to match.
193 | * @return The character.
194 | * @throws JSONException if the character does not match.
195 | */
196 | public char next(char c) throws JSONException {
197 | char n = this.next();
198 | if (n != c) {
199 | throw this.syntaxError("Expected '" + c + "' and instead saw '" +
200 | n + "'");
201 | }
202 | return n;
203 | }
204 |
205 |
206 | /**
207 | * Get the next n characters.
208 | *
209 | * @param n The number of characters to take.
210 | * @return A string of n characters.
211 | * @throws JSONException
212 | * Substring bounds error if there are not
213 | * n characters remaining in the source string.
214 | */
215 | public String next(int n) throws JSONException {
216 | if (n == 0) {
217 | return "";
218 | }
219 |
220 | char[] chars = new char[n];
221 | int pos = 0;
222 |
223 | while (pos < n) {
224 | chars[pos] = this.next();
225 | if (this.end()) {
226 | throw this.syntaxError("Substring bounds error");
227 | }
228 | pos += 1;
229 | }
230 | return new String(chars);
231 | }
232 |
233 |
234 | /**
235 | * Get the next char in the string, skipping whitespace.
236 | * @throws JSONException Thrown if there is an error reading the source string.
237 | * @return A character, or 0 if there are no more characters.
238 | */
239 | public char nextClean() throws JSONException {
240 | for (;;) {
241 | char c = this.next();
242 | if (c == 0 || c > ' ') {
243 | return c;
244 | }
245 | }
246 | }
247 |
248 |
249 | /**
250 | * Return the characters up to the next close quote character.
251 | * Backslash processing is done. The formal JSON format does not
252 | * allow strings in single quotes, but an implementation is allowed to
253 | * accept them.
254 | * @param quote The quoting character, either
255 | * "
(double quote) or
256 | * '
(single quote).
257 | * @return A String.
258 | * @throws JSONException Unterminated string.
259 | */
260 | public String nextString(char quote) throws JSONException {
261 | char c;
262 | StringBuilder sb = new StringBuilder();
263 | for (;;) {
264 | c = this.next();
265 | switch (c) {
266 | case 0:
267 | case '\n':
268 | case '\r':
269 | throw this.syntaxError("Unterminated string");
270 | case '\\':
271 | c = this.next();
272 | switch (c) {
273 | case 'b':
274 | sb.append('\b');
275 | break;
276 | case 't':
277 | sb.append('\t');
278 | break;
279 | case 'n':
280 | sb.append('\n');
281 | break;
282 | case 'f':
283 | sb.append('\f');
284 | break;
285 | case 'r':
286 | sb.append('\r');
287 | break;
288 | case 'u':
289 | try {
290 | sb.append((char)Integer.parseInt(this.next(4), 16));
291 | } catch (NumberFormatException e) {
292 | throw this.syntaxError("Illegal escape.", e);
293 | }
294 | break;
295 | case '"':
296 | case '\'':
297 | case '\\':
298 | case '/':
299 | sb.append(c);
300 | break;
301 | default:
302 | throw this.syntaxError("Illegal escape.");
303 | }
304 | break;
305 | default:
306 | if (c == quote) {
307 | return sb.toString();
308 | }
309 | sb.append(c);
310 | }
311 | }
312 | }
313 |
314 |
315 | /**
316 | * Get the text up but not including the specified character or the
317 | * end of line, whichever comes first.
318 | * @param delimiter A delimiter character.
319 | * @return A string.
320 | * @throws JSONException Thrown if there is an error while searching
321 | * for the delimiter
322 | */
323 | public String nextTo(char delimiter) throws JSONException {
324 | StringBuilder sb = new StringBuilder();
325 | for (;;) {
326 | char c = this.next();
327 | if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
328 | if (c != 0) {
329 | this.back();
330 | }
331 | return sb.toString().trim();
332 | }
333 | sb.append(c);
334 | }
335 | }
336 |
337 |
338 | /**
339 | * Get the text up but not including one of the specified delimiter
340 | * characters or the end of line, whichever comes first.
341 | * @param delimiters A set of delimiter characters.
342 | * @return A string, trimmed.
343 | * @throws JSONException Thrown if there is an error while searching
344 | * for the delimiter
345 | */
346 | public String nextTo(String delimiters) throws JSONException {
347 | char c;
348 | StringBuilder sb = new StringBuilder();
349 | for (;;) {
350 | c = this.next();
351 | if (delimiters.indexOf(c) >= 0 || c == 0 ||
352 | c == '\n' || c == '\r') {
353 | if (c != 0) {
354 | this.back();
355 | }
356 | return sb.toString().trim();
357 | }
358 | sb.append(c);
359 | }
360 | }
361 |
362 |
363 | /**
364 | * Get the next value. The value can be a Boolean, Double, Integer,
365 | * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
366 | * @throws JSONException If syntax error.
367 | *
368 | * @return An object.
369 | */
370 | public Object nextValue() throws JSONException {
371 | char c = this.nextClean();
372 | String string;
373 |
374 | switch (c) {
375 | case '"':
376 | case '\'':
377 | return this.nextString(c);
378 | case '{':
379 | this.back();
380 | return new JSONObject(this);
381 | case '[':
382 | this.back();
383 | return new JSONArray(this);
384 | }
385 |
386 | /*
387 | * Handle unquoted text. This could be the values true, false, or
388 | * null, or it can be a number. An implementation (such as this one)
389 | * is allowed to also accept non-standard forms.
390 | *
391 | * Accumulate characters until we reach the end of the text or a
392 | * formatting character.
393 | */
394 |
395 | StringBuilder sb = new StringBuilder();
396 | while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
397 | sb.append(c);
398 | c = this.next();
399 | }
400 | this.back();
401 |
402 | string = sb.toString().trim();
403 | if ("".equals(string)) {
404 | throw this.syntaxError("Missing value");
405 | }
406 | return JSONObject.stringToValue(string);
407 | }
408 |
409 |
410 | /**
411 | * Skip characters until the next character is the requested character.
412 | * If the requested character is not found, no characters are skipped.
413 | * @param to A character to skip to.
414 | * @return The requested character, or zero if the requested character
415 | * is not found.
416 | * @throws JSONException Thrown if there is an error while searching
417 | * for the to character
418 | */
419 | public char skipTo(char to) throws JSONException {
420 | char c;
421 | try {
422 | long startIndex = this.index;
423 | long startCharacter = this.character;
424 | long startLine = this.line;
425 | this.reader.mark(1000000);
426 | do {
427 | c = this.next();
428 | if (c == 0) {
429 | this.reader.reset();
430 | this.index = startIndex;
431 | this.character = startCharacter;
432 | this.line = startLine;
433 | return c;
434 | }
435 | } while (c != to);
436 | } catch (IOException exception) {
437 | throw new JSONException(exception);
438 | }
439 | this.back();
440 | return c;
441 | }
442 |
443 |
444 | /**
445 | * Make a JSONException to signal a syntax error.
446 | *
447 | * @param message The error message.
448 | * @return A JSONException object, suitable for throwing
449 | */
450 | public JSONException syntaxError(String message) {
451 | return new JSONException(message + this.toString());
452 | }
453 |
454 | /**
455 | * Make a JSONException to signal a syntax error.
456 | *
457 | * @param message The error message.
458 | * @param causedBy The throwable that caused the error.
459 | * @return A JSONException object, suitable for throwing
460 | */
461 | public JSONException syntaxError(String message, Throwable causedBy) {
462 | return new JSONException(message + this.toString(), causedBy);
463 | }
464 |
465 | /**
466 | * Make a printable string of this JSONTokener.
467 | *
468 | * @return " at {index} [character {character} line {line}]"
469 | */
470 | @Override
471 | public String toString() {
472 | return " at " + this.index + " [character " + this.character + " line " +
473 | this.line + "]";
474 | }
475 | }
476 |
--------------------------------------------------------------------------------
/src/org/json/JSONWriter.java:
--------------------------------------------------------------------------------
1 | package org.json;
2 |
3 | import java.io.IOException;
4 | import java.io.Writer;
5 |
6 | /*
7 | Copyright (c) 2006 JSON.org
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in all
17 | copies or substantial portions of the Software.
18 |
19 | The Software shall be used for Good, not Evil.
20 |
21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | SOFTWARE.
28 | */
29 |
30 | /**
31 | * JSONWriter provides a quick and convenient way of producing JSON text.
32 | * The texts produced strictly conform to JSON syntax rules. No whitespace is
33 | * added, so the results are ready for transmission or storage. Each instance of
34 | * JSONWriter can produce one JSON text.
35 | * value
method for appending
37 | * values to the
38 | * text, and a key
39 | * method for adding keys before values in objects. There are array
40 | * and endArray
methods that make and bound array values, and
41 | * object
and endObject
methods which make and bound
42 | * object values. All of these methods return the JSONWriter instance,
43 | * permitting a cascade style. For example,
44 | * new JSONWriter(myWriter)
45 | * .object()
46 | * .key("JSON")
47 | * .value("Hello, World!")
48 | * .endObject();
which writes
49 | * {"JSON":"Hello, World!"}
50 | * array
or object
.
52 | * There are no methods for adding commas or colons. JSONWriter adds them for
53 | * you. Objects and arrays can be nested up to 20 levels deep.
54 | * endArray
will be appended to this array. The
135 | * endArray
method must be called to mark the array's end.
136 | * @return this
137 | * @throws JSONException If the nesting is too deep, or if the object is
138 | * started in the wrong place (for example as a key or after the end of the
139 | * outermost array or object).
140 | */
141 | public JSONWriter array() throws JSONException {
142 | if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
143 | this.push(null);
144 | this.append("[");
145 | this.comma = false;
146 | return this;
147 | }
148 | throw new JSONException("Misplaced array.");
149 | }
150 |
151 | /**
152 | * End something.
153 | * @param mode Mode
154 | * @param c Closing character
155 | * @return this
156 | * @throws JSONException If unbalanced.
157 | */
158 | private JSONWriter end(char mode, char c) throws JSONException {
159 | if (this.mode != mode) {
160 | throw new JSONException(mode == 'a'
161 | ? "Misplaced endArray."
162 | : "Misplaced endObject.");
163 | }
164 | this.pop(mode);
165 | try {
166 | this.writer.write(c);
167 | } catch (IOException e) {
168 | throw new JSONException(e);
169 | }
170 | this.comma = true;
171 | return this;
172 | }
173 |
174 | /**
175 | * End an array. This method most be called to balance calls to
176 | * array
.
177 | * @return this
178 | * @throws JSONException If incorrectly nested.
179 | */
180 | public JSONWriter endArray() throws JSONException {
181 | return this.end('a', ']');
182 | }
183 |
184 | /**
185 | * End an object. This method most be called to balance calls to
186 | * object
.
187 | * @return this
188 | * @throws JSONException If incorrectly nested.
189 | */
190 | public JSONWriter endObject() throws JSONException {
191 | return this.end('k', '}');
192 | }
193 |
194 | /**
195 | * Append a key. The key will be associated with the next value. In an
196 | * object, every value must be preceded by a key.
197 | * @param string A key string.
198 | * @return this
199 | * @throws JSONException If the key is out of place. For example, keys
200 | * do not belong in arrays or if the key is null.
201 | */
202 | public JSONWriter key(String string) throws JSONException {
203 | if (string == null) {
204 | throw new JSONException("Null key.");
205 | }
206 | if (this.mode == 'k') {
207 | try {
208 | this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
209 | if (this.comma) {
210 | this.writer.write(',');
211 | }
212 | this.writer.write(JSONObject.quote(string));
213 | this.writer.write(':');
214 | this.comma = false;
215 | this.mode = 'o';
216 | return this;
217 | } catch (IOException e) {
218 | throw new JSONException(e);
219 | }
220 | }
221 | throw new JSONException("Misplaced key.");
222 | }
223 |
224 |
225 | /**
226 | * Begin appending a new object. All keys and values until the balancing
227 | * endObject
will be appended to this object. The
228 | * endObject
method must be called to mark the object's end.
229 | * @return this
230 | * @throws JSONException If the nesting is too deep, or if the object is
231 | * started in the wrong place (for example as a key or after the end of the
232 | * outermost array or object).
233 | */
234 | public JSONWriter object() throws JSONException {
235 | if (this.mode == 'i') {
236 | this.mode = 'o';
237 | }
238 | if (this.mode == 'o' || this.mode == 'a') {
239 | this.append("{");
240 | this.push(new JSONObject());
241 | this.comma = false;
242 | return this;
243 | }
244 | throw new JSONException("Misplaced object.");
245 |
246 | }
247 |
248 |
249 | /**
250 | * Pop an array or object scope.
251 | * @param c The scope to close.
252 | * @throws JSONException If nesting is wrong.
253 | */
254 | private void pop(char c) throws JSONException {
255 | if (this.top <= 0) {
256 | throw new JSONException("Nesting error.");
257 | }
258 | char m = this.stack[this.top - 1] == null ? 'a' : 'k';
259 | if (m != c) {
260 | throw new JSONException("Nesting error.");
261 | }
262 | this.top -= 1;
263 | this.mode = this.top == 0
264 | ? 'd'
265 | : this.stack[this.top - 1] == null
266 | ? 'a'
267 | : 'k';
268 | }
269 |
270 | /**
271 | * Push an array or object scope.
272 | * @param jo The scope to open.
273 | * @throws JSONException If nesting is too deep.
274 | */
275 | private void push(JSONObject jo) throws JSONException {
276 | if (this.top >= maxdepth) {
277 | throw new JSONException("Nesting too deep.");
278 | }
279 | this.stack[this.top] = jo;
280 | this.mode = jo == null ? 'a' : 'k';
281 | this.top += 1;
282 | }
283 |
284 |
285 | /**
286 | * Append either the value true
or the value
287 | * false
.
288 | * @param b A boolean.
289 | * @return this
290 | * @throws JSONException
291 | */
292 | public JSONWriter value(boolean b) throws JSONException {
293 | return this.append(b ? "true" : "false");
294 | }
295 |
296 | /**
297 | * Append a double value.
298 | * @param d A double.
299 | * @return this
300 | * @throws JSONException If the number is not finite.
301 | */
302 | public JSONWriter value(double d) throws JSONException {
303 | return this.value(new Double(d));
304 | }
305 |
306 | /**
307 | * Append a long value.
308 | * @param l A long.
309 | * @return this
310 | * @throws JSONException
311 | */
312 | public JSONWriter value(long l) throws JSONException {
313 | return this.append(Long.toString(l));
314 | }
315 |
316 |
317 | /**
318 | * Append an object value.
319 | * @param object The object to append. It can be null, or a Boolean, Number,
320 | * String, JSONObject, or JSONArray, or an object that implements JSONString.
321 | * @return this
322 | * @throws JSONException If the value is out of sequence.
323 | */
324 | public JSONWriter value(Object object) throws JSONException {
325 | return this.append(JSONObject.valueToString(object));
326 | }
327 | }
328 |
--------------------------------------------------------------------------------
/src/org/json/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2002 JSON.org
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | The Software shall be used for Good, not Evil.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/org/json/Property.java:
--------------------------------------------------------------------------------
1 | package org.json;
2 |
3 | /*
4 | Copyright (c) 2002 JSON.org
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | The Software shall be used for Good, not Evil.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | */
26 |
27 | import java.util.Enumeration;
28 | import java.util.Iterator;
29 | import java.util.Properties;
30 |
31 | /**
32 | * Converts a Property file data into JSONObject and back.
33 | * @author JSON.org
34 | * @version 2015-05-05
35 | */
36 | public class Property {
37 | /**
38 | * Converts a property file object into a JSONObject. The property file object is a table of name value pairs.
39 | * @param properties java.util.Properties
40 | * @return JSONObject
41 | * @throws JSONException
42 | */
43 | public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException {
44 | JSONObject jo = new JSONObject();
45 | if (properties != null && !properties.isEmpty()) {
46 | Enumeration> enumProperties = properties.propertyNames();
47 | while(enumProperties.hasMoreElements()) {
48 | String name = (String)enumProperties.nextElement();
49 | jo.put(name, properties.getProperty(name));
50 | }
51 | }
52 | return jo;
53 | }
54 |
55 | /**
56 | * Converts the JSONObject into a property file object.
57 | * @param jo JSONObject
58 | * @return java.util.Properties
59 | * @throws JSONException
60 | */
61 | public static Properties toProperties(JSONObject jo) throws JSONException {
62 | Properties properties = new Properties();
63 | if (jo != null) {
64 | Iterator
70 | * & (ampersand) is replaced by &
71 | * < (less than) is replaced by <
72 | * > (greater than) is replaced by >
73 | * " (double quote) is replaced by "
74 | *
75 | *
76 | * @param string
77 | * The string to be escaped.
78 | * @return The escaped string.
79 | */
80 | public static String escape(String string) {
81 | StringBuilder sb = new StringBuilder(string.length());
82 | for (int i = 0, length = string.length(); i < length; i++) {
83 | char c = string.charAt(i);
84 | switch (c) {
85 | case '&':
86 | sb.append("&");
87 | break;
88 | case '<':
89 | sb.append("<");
90 | break;
91 | case '>':
92 | sb.append(">");
93 | break;
94 | case '"':
95 | sb.append(""");
96 | break;
97 | case '\'':
98 | sb.append("'");
99 | break;
100 | default:
101 | sb.append(c);
102 | }
103 | }
104 | return sb.toString();
105 | }
106 |
107 | /**
108 | * Throw an exception if the string contains whitespace. Whitespace is not
109 | * allowed in tagNames and attributes.
110 | *
111 | * @param string
112 | * A string.
113 | * @throws JSONException Thrown if the string contains whitespace or is empty.
114 | */
115 | public static void noSpace(String string) throws JSONException {
116 | int i, length = string.length();
117 | if (length == 0) {
118 | throw new JSONException("Empty string.");
119 | }
120 | for (i = 0; i < length; i += 1) {
121 | if (Character.isWhitespace(string.charAt(i))) {
122 | throw new JSONException("'" + string
123 | + "' contains a space character.");
124 | }
125 | }
126 | }
127 |
128 | /**
129 | * Scan the content following the named tag, attaching it to the context.
130 | *
131 | * @param x
132 | * The XMLTokener containing the source string.
133 | * @param context
134 | * The JSONObject that will include the new material.
135 | * @param name
136 | * The tag name.
137 | * @return true if the close tag is processed.
138 | * @throws JSONException
139 | */
140 | private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings)
141 | throws JSONException {
142 | char c;
143 | int i;
144 | JSONObject jsonobject = null;
145 | String string;
146 | String tagName;
147 | Object token;
148 |
149 | // Test for and skip past these forms:
150 | //
151 | //
152 | //
153 | // ... ?>
154 | // Report errors for these forms:
155 | // <>
156 | // <=
157 | // <<
158 |
159 | token = x.nextToken();
160 |
161 | // ");
168 | return false;
169 | }
170 | x.back();
171 | } else if (c == '[') {
172 | token = x.nextToken();
173 | if ("CDATA".equals(token)) {
174 | if (x.next() == '[') {
175 | string = x.nextCDATA();
176 | if (string.length() > 0) {
177 | context.accumulate("content", string);
178 | }
179 | return false;
180 | }
181 | }
182 | throw x.syntaxError("Expected 'CDATA['");
183 | }
184 | i = 1;
185 | do {
186 | token = x.nextMeta();
187 | if (token == null) {
188 | throw x.syntaxError("Missing '>' after ' 0);
195 | return false;
196 | } else if (token == QUEST) {
197 |
198 | //
199 | x.skipPast("?>");
200 | return false;
201 | } else if (token == SLASH) {
202 |
203 | // Close tag
204 |
205 | token = x.nextToken();
206 | if (name == null) {
207 | throw x.syntaxError("Mismatched close tag " + token);
208 | }
209 | if (!token.equals(name)) {
210 | throw x.syntaxError("Mismatched " + name + " and " + token);
211 | }
212 | if (x.nextToken() != GT) {
213 | throw x.syntaxError("Misshaped close tag");
214 | }
215 | return true;
216 |
217 | } else if (token instanceof Character) {
218 | throw x.syntaxError("Misshaped tag");
219 |
220 | // Open tag <
221 |
222 | } else {
223 | tagName = (String) token;
224 | token = null;
225 | jsonobject = new JSONObject();
226 | for (;;) {
227 | if (token == null) {
228 | token = x.nextToken();
229 | }
230 |
231 | // attribute = value
232 | if (token instanceof String) {
233 | string = (String) token;
234 | token = x.nextToken();
235 | if (token == EQ) {
236 | token = x.nextToken();
237 | if (!(token instanceof String)) {
238 | throw x.syntaxError("Missing value");
239 | }
240 | jsonobject.accumulate(string,
241 | keepStrings ? token : JSONObject.stringToValue((String) token));
242 | token = null;
243 | } else {
244 | jsonobject.accumulate(string, "");
245 | }
246 |
247 |
248 | } else if (token == SLASH) {
249 | // Empty tag <.../>
250 | if (x.nextToken() != GT) {
251 | throw x.syntaxError("Misshaped tag");
252 | }
253 | if (jsonobject.length() > 0) {
254 | context.accumulate(tagName, jsonobject);
255 | } else {
256 | context.accumulate(tagName, "");
257 | }
258 | return false;
259 |
260 | } else if (token == GT) {
261 | // Content, between <...> and
262 | for (;;) {
263 | token = x.nextContent();
264 | if (token == null) {
265 | if (tagName != null) {
266 | throw x.syntaxError("Unclosed tag " + tagName);
267 | }
268 | return false;
269 | } else if (token instanceof String) {
270 | string = (String) token;
271 | if (string.length() > 0) {
272 | jsonobject.accumulate("content",
273 | keepStrings ? token : JSONObject.stringToValue(string));
274 | }
275 |
276 | } else if (token == LT) {
277 | // Nested element
278 | if (parse(x, jsonobject, tagName,keepStrings)) {
279 | if (jsonobject.length() == 0) {
280 | context.accumulate(tagName, "");
281 | } else if (jsonobject.length() == 1
282 | && jsonobject.opt("content") != null) {
283 | context.accumulate(tagName,
284 | jsonobject.opt("content"));
285 | } else {
286 | context.accumulate(tagName, jsonobject);
287 | }
288 | return false;
289 | }
290 | }
291 | }
292 | } else {
293 | throw x.syntaxError("Misshaped tag");
294 | }
295 | }
296 | }
297 | }
298 |
299 | /**
300 | * This method has been deprecated in favor of the
301 | * {@link JSONObject.stringToValue(String)} method. Use it instead.
302 | *
303 | * @deprecated Use {@link JSONObject#stringToValue(String)} instead.
304 | * @param string String to convert
305 | * @return JSON value of this string or the string
306 | */
307 | @Deprecated
308 | public static Object stringToValue(String string) {
309 | return JSONObject.stringToValue(string);
310 | }
311 |
312 | /**
313 | * Convert a well-formed (but not necessarily valid) XML string into a
314 | * JSONObject. Some information may be lost in this transformation because
315 | * JSON is a data format and XML is a document format. XML uses elements,
316 | * attributes, and content text, while JSON uses unordered collections of
317 | * name/value pairs and arrays of values. JSON does not does not like to
318 | * distinguish between elements and attributes. Sequences of similar
319 | * elements are represented as JSONArrays. Content text may be placed in a
320 | * "content" member. Comments, prologs, DTDs, and <[ [ ]]>
321 | * are ignored.
322 | *
323 | * @param string
324 | * The source string.
325 | * @return A JSONObject containing the structured data from the XML string.
326 | * @throws JSONException Thrown if there is an errors while parsing the string
327 | */
328 | public static JSONObject toJSONObject(String string) throws JSONException {
329 | return toJSONObject(string, false);
330 | }
331 |
332 |
333 | /**
334 | * Convert a well-formed (but not necessarily valid) XML string into a
335 | * JSONObject. Some information may be lost in this transformation because
336 | * JSON is a data format and XML is a document format. XML uses elements,
337 | * attributes, and content text, while JSON uses unordered collections of
338 | * name/value pairs and arrays of values. JSON does not does not like to
339 | * distinguish between elements and attributes. Sequences of similar
340 | * elements are represented as JSONArrays. Content text may be placed in a
341 | * "content" member. Comments, prologs, DTDs, and <[ [ ]]>
342 | * are ignored.
343 | *
344 | * All values are converted as strings, for 1, 01, 29.0 will not be coerced to
345 | * numbers but will instead be the exact value as seen in the XML document.
346 | *
347 | * @param string
348 | * The source string.
349 | * @param keepStrings If true, then values will not be coerced into boolean
350 | * or numeric values and will instead be left as strings
351 | * @return A JSONObject containing the structured data from the XML string.
352 | * @throws JSONException Thrown if there is an errors while parsing the string
353 | */
354 | public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
355 | JSONObject jo = new JSONObject();
356 | XMLTokener x = new XMLTokener(string);
357 | while (x.more() && x.skipPast("<")) {
358 | parse(x, jo, null, keepStrings);
359 | }
360 | return jo;
361 | }
362 | /**
363 | * Convert a JSONObject into a well-formed, element-normal XML string.
364 | *
365 | * @param object
366 | * A JSONObject.
367 | * @return A string.
368 | * @throws JSONException Thrown if there is an error parsing the string
369 | */
370 | public static String toString(Object object) throws JSONException {
371 | return toString(object, null);
372 | }
373 |
374 | /**
375 | * Convert a JSONObject into a well-formed, element-normal XML string.
376 | *
377 | * @param object
378 | * A JSONObject.
379 | * @param tagName
380 | * The optional name of the enclosing tag.
381 | * @return A string.
382 | * @throws JSONException Thrown if there is an error parsing the string
383 | */
384 | public static String toString(Object object, String tagName)
385 | throws JSONException {
386 | StringBuilder sb = new StringBuilder();
387 | JSONArray ja;
388 | JSONObject jo;
389 | String key;
390 | Iterator]]>
.
61 | * @throws JSONException If the ]]>
is not found.
62 | */
63 | public String nextCDATA() throws JSONException {
64 | char c;
65 | int i;
66 | StringBuilder sb = new StringBuilder();
67 | for (;;) {
68 | c = next();
69 | if (end()) {
70 | throw syntaxError("Unclosed CDATA");
71 | }
72 | sb.append(c);
73 | i = sb.length() - 3;
74 | if (i >= 0 && sb.charAt(i) == ']' &&
75 | sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
76 | sb.setLength(i);
77 | return sb.toString();
78 | }
79 | }
80 | }
81 |
82 |
83 | /**
84 | * Get the next XML outer token, trimming whitespace. There are two kinds
85 | * of tokens: the '<' character which begins a markup tag, and the content
86 | * text between markup tags.
87 | *
88 | * @return A string, or a '<' Character, or null if there is no more
89 | * source text.
90 | * @throws JSONException
91 | */
92 | public Object nextContent() throws JSONException {
93 | char c;
94 | StringBuilder sb;
95 | do {
96 | c = next();
97 | } while (Character.isWhitespace(c));
98 | if (c == 0) {
99 | return null;
100 | }
101 | if (c == '<') {
102 | return XML.LT;
103 | }
104 | sb = new StringBuilder();
105 | for (;;) {
106 | if (c == '<' || c == 0) {
107 | back();
108 | return sb.toString().trim();
109 | }
110 | if (c == '&') {
111 | sb.append(nextEntity(c));
112 | } else {
113 | sb.append(c);
114 | }
115 | c = next();
116 | }
117 | }
118 |
119 |
120 | /**
121 | * Return the next entity. These entities are translated to Characters:
122 | * & ' > < "
.
123 | * @param ampersand An ampersand character.
124 | * @return A Character or an entity String if the entity is not recognized.
125 | * @throws JSONException If missing ';' in XML entity.
126 | */
127 | public Object nextEntity(char ampersand) throws JSONException {
128 | StringBuilder sb = new StringBuilder();
129 | for (;;) {
130 | char c = next();
131 | if (Character.isLetterOrDigit(c) || c == '#') {
132 | sb.append(Character.toLowerCase(c));
133 | } else if (c == ';') {
134 | break;
135 | } else {
136 | throw syntaxError("Missing ';' in XML entity: &" + sb);
137 | }
138 | }
139 | String string = sb.toString();
140 | Object object = entity.get(string);
141 | return object != null ? object : ampersand + string + ";";
142 | }
143 |
144 |
145 | /**
146 | * Returns the next XML meta token. This is used for skipping over
147 | * and ...?> structures.
148 | * @return Syntax characters (< > / = ! ?
) are returned as
149 | * Character, and strings and names are returned as Boolean. We don't care
150 | * what the values actually are.
151 | * @throws JSONException If a string is not properly closed or if the XML
152 | * is badly structured.
153 | */
154 | public Object nextMeta() throws JSONException {
155 | char c;
156 | char q;
157 | do {
158 | c = next();
159 | } while (Character.isWhitespace(c));
160 | switch (c) {
161 | case 0:
162 | throw syntaxError("Misshaped meta tag");
163 | case '<':
164 | return XML.LT;
165 | case '>':
166 | return XML.GT;
167 | case '/':
168 | return XML.SLASH;
169 | case '=':
170 | return XML.EQ;
171 | case '!':
172 | return XML.BANG;
173 | case '?':
174 | return XML.QUEST;
175 | case '"':
176 | case '\'':
177 | q = c;
178 | for (;;) {
179 | c = next();
180 | if (c == 0) {
181 | throw syntaxError("Unterminated string");
182 | }
183 | if (c == q) {
184 | return Boolean.TRUE;
185 | }
186 | }
187 | default:
188 | for (;;) {
189 | c = next();
190 | if (Character.isWhitespace(c)) {
191 | return Boolean.TRUE;
192 | }
193 | switch (c) {
194 | case 0:
195 | case '<':
196 | case '>':
197 | case '/':
198 | case '=':
199 | case '!':
200 | case '?':
201 | case '"':
202 | case '\'':
203 | back();
204 | return Boolean.TRUE;
205 | }
206 | }
207 | }
208 | }
209 |
210 |
211 | /**
212 | * Get the next XML Token. These tokens are found inside of angle
213 | * brackets. It may be one of these characters: / > = ! ?
or it
214 | * may be a string wrapped in single quotes or double quotes, or it may be a
215 | * name.
216 | * @return a String or a Character.
217 | * @throws JSONException If the XML is not well formed.
218 | */
219 | public Object nextToken() throws JSONException {
220 | char c;
221 | char q;
222 | StringBuilder sb;
223 | do {
224 | c = next();
225 | } while (Character.isWhitespace(c));
226 | switch (c) {
227 | case 0:
228 | throw syntaxError("Misshaped element");
229 | case '<':
230 | throw syntaxError("Misplaced '<'");
231 | case '>':
232 | return XML.GT;
233 | case '/':
234 | return XML.SLASH;
235 | case '=':
236 | return XML.EQ;
237 | case '!':
238 | return XML.BANG;
239 | case '?':
240 | return XML.QUEST;
241 |
242 | // Quoted string
243 |
244 | case '"':
245 | case '\'':
246 | q = c;
247 | sb = new StringBuilder();
248 | for (;;) {
249 | c = next();
250 | if (c == 0) {
251 | throw syntaxError("Unterminated string");
252 | }
253 | if (c == q) {
254 | return sb.toString();
255 | }
256 | if (c == '&') {
257 | sb.append(nextEntity(c));
258 | } else {
259 | sb.append(c);
260 | }
261 | }
262 | default:
263 |
264 | // Name
265 |
266 | sb = new StringBuilder();
267 | for (;;) {
268 | sb.append(c);
269 | c = next();
270 | if (Character.isWhitespace(c)) {
271 | return sb.toString();
272 | }
273 | switch (c) {
274 | case 0:
275 | return sb.toString();
276 | case '>':
277 | case '/':
278 | case '=':
279 | case '!':
280 | case '?':
281 | case '[':
282 | case ']':
283 | back();
284 | return sb.toString();
285 | case '<':
286 | case '"':
287 | case '\'':
288 | throw syntaxError("Bad character in a name");
289 | }
290 | }
291 | }
292 | }
293 |
294 |
295 | /**
296 | * Skip characters until past the requested string.
297 | * If it is not found, we are left at the end of the source with a result of false.
298 | * @param to A string to skip past.
299 | * @throws JSONException
300 | */
301 | public boolean skipPast(String to) throws JSONException {
302 | boolean b;
303 | char c;
304 | int i;
305 | int j;
306 | int offset = 0;
307 | int length = to.length();
308 | char[] circle = new char[length];
309 |
310 | /*
311 | * First fill the circle buffer with as many characters as are in the
312 | * to string. If we reach an early end, bail.
313 | */
314 |
315 | for (i = 0; i < length; i += 1) {
316 | c = next();
317 | if (c == 0) {
318 | return false;
319 | }
320 | circle[i] = c;
321 | }
322 |
323 | /* We will loop, possibly for all of the remaining characters. */
324 |
325 | for (;;) {
326 | j = offset;
327 | b = true;
328 |
329 | /* Compare the circle buffer with the to string. */
330 |
331 | for (i = 0; i < length; i += 1) {
332 | if (circle[j] != to.charAt(i)) {
333 | b = false;
334 | break;
335 | }
336 | j += 1;
337 | if (j >= length) {
338 | j -= length;
339 | }
340 | }
341 |
342 | /* If we exit the loop with b intact, then victory is ours. */
343 |
344 | if (b) {
345 | return true;
346 | }
347 |
348 | /* Get the next character. If there isn't one, then defeat is ours. */
349 |
350 | c = next();
351 | if (c == 0) {
352 | return false;
353 | }
354 | /*
355 | * Shove the character in the circle buffer and advance the
356 | * circle offset. The offset is mod n.
357 | */
358 | circle[offset] = c;
359 | offset += 1;
360 | if (offset >= length) {
361 | offset -= length;
362 | }
363 | }
364 | }
365 | }
366 |
--------------------------------------------------------------------------------