├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
└── src
└── cc
└── nnproject
└── json
├── AbstractJSON.java
├── BufferedReader.java
├── JSON.java
├── JSONArray.java
├── JSONException.java
├── JSONObject.java
└── JSONStream.java
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.jar
2 | *.zip
3 | # Compiled classes folder
4 | bin
5 | # Eclipse settings
6 | .settings
7 |
8 | .project
9 | .classpath
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Arman Jussupgaliyev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cc.nnproject.json
2 | JSON library for Java, compatible with CLDC 1.1 & JDK 1.1
3 |
4 | ## Usage example:
5 |
6 | `JSON`:
7 | ```
8 | JSONObject json = JSON.getObject(str);
9 | System.out.println(json.getArray("messages").getObject(0).getNullableString("text"));
10 | ```
11 |
12 | `JSONArray`, `JSONObject`:
13 | ```
14 | JSONArray objects = new JSONArray();
15 |
16 | JSONObject object1 = new JSONObject();
17 | object1.put("some", "Example text");
18 | objects.add(object1);
19 |
20 | JSONObject object2 = new JSONObject();
21 | object2.put("n", 292);
22 | objects.add(object2);
23 |
24 | System.out.println(objects.build());
25 | ```
26 |
27 | `JSONStream`:
28 | ```
29 | JSONStream stream = JSONStream.getStream(connection.openInputStream());
30 | try {
31 | stream.expectNextTrim('{');
32 |
33 | if(!stream.jumpToKey("response")) return;
34 | stream.expectNextTrim('{');
35 |
36 | if(!stream.jumpToKey("items")) return;
37 | stream.expectNextTrim('[');
38 |
39 | if(!stream.skipArrayElements(3)) return;
40 | stream.expectNextTrim('{');
41 |
42 | if(!stream.jumpToKey("date")) return;
43 |
44 | System.out.println(stream.nextValue());
45 | } finally {
46 | stream.close();
47 | }
48 | ```
49 |
--------------------------------------------------------------------------------
/src/cc/nnproject/json/AbstractJSON.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2022-2025 Arman Jussupgaliyev
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 | package cc.nnproject.json;
23 |
24 | import java.io.IOException;
25 | import java.io.OutputStream;
26 |
27 | public abstract class AbstractJSON {
28 |
29 | // common methods for both JSONObject and JSONArray
30 |
31 | public abstract void clear();
32 |
33 | public abstract int size();
34 |
35 | public abstract String toString();
36 |
37 | public abstract String build();
38 |
39 | public final String format() {
40 | return format(0);
41 | }
42 |
43 | public abstract void write(OutputStream out) throws IOException;
44 |
45 | protected abstract String format(int l);
46 |
47 | public abstract boolean similar(Object obj);
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/cc/nnproject/json/BufferedReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
3 | * All rights reserved.
4 | * This component and the accompanying materials are made available
5 | * under the terms of "Eclipse Public License v1.0"
6 | * which accompanies this distribution, and is available
7 | * at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 | *
9 | * Initial Contributors:
10 | * Nokia Corporation - initial contribution.
11 | *
12 | * Contributors:
13 | *
14 | * Description:
15 | *
16 | */
17 |
18 |
19 | package cc.nnproject.json;
20 |
21 | import java.io.IOException;
22 | import java.io.Reader;
23 |
24 | /**
25 | * Buffered wrapper for Readers.
26 | *
27 | * @see java.io.BufferedReader
28 | */
29 | public class BufferedReader extends Reader
30 | {
31 | /** Default buffer size. */
32 | private static final int BUF_SIZE = 16384;
33 |
34 | /** Reader given in the constructor. */
35 | private Reader iReader = null;
36 |
37 | /** Character buffer. */
38 | private char[] iBuf = null;
39 |
40 | /** Amount of characters in the buffer.
41 | Value must be between zero and iBuf.length. */
42 | private int iBufAmount = 0;
43 |
44 | /** Current read position in the buffer.
45 | Value must be between zero and iBuf.length. */
46 | private int iBufPos = 0;
47 |
48 | /**
49 | * @see java.io.BufferedReader#Constructor(java.io.Reader)
50 | */
51 | public BufferedReader(Reader aIn)
52 | {
53 | this(aIn, BUF_SIZE);
54 | }
55 |
56 | /**
57 | * @see java.io.BufferedReader#Constructor(java.io.Reader, int)
58 | */
59 | public BufferedReader(Reader aIn, int aSize)
60 | {
61 | if (aSize <= 0)
62 | {
63 | throw new IllegalArgumentException(
64 | "BufferedReader: Invalid buffer size");
65 | }
66 | iBuf = new char[aSize];
67 | iReader = aIn;
68 | }
69 |
70 | /**
71 | * @see java.io.BufferedReader#close()
72 | */
73 | public void close() throws IOException
74 | {
75 | iBuf = null;
76 | iBufAmount = 0;
77 | iBufPos = 0;
78 | if (iReader != null)
79 | {
80 | iReader.close();
81 | }
82 | }
83 |
84 | /**
85 | * @see java.io.BufferedReader#read()
86 | */
87 | public int read() throws IOException
88 | {
89 | int result = 0;
90 | if (iBufPos >= iBufAmount)
91 | {
92 | result = fillBuf();
93 | }
94 | if (result > -1)
95 | {
96 | result = iBuf[iBufPos++];
97 | }
98 | return result;
99 | }
100 |
101 | /**
102 | * @see java.io.BufferedReader#read(char[])
103 | */
104 | public int read(char[] aBuf) throws IOException
105 | {
106 | return read(aBuf, 0, aBuf.length);
107 | }
108 |
109 | /**
110 | * @see java.io.BufferedReader#read(char[], int, int)
111 | */
112 | public int read(char[] aBuf, int aOffset, int aLength) throws IOException
113 | {
114 | if (aOffset < 0 || aOffset >= aBuf.length)
115 | {
116 | throw new IllegalArgumentException(
117 | "BufferedReader: Invalid buffer offset");
118 | }
119 | int charsToRead = aBuf.length - aOffset;
120 | if (charsToRead > aLength)
121 | {
122 | charsToRead = aLength;
123 | }
124 | int bufCharCount = iBufAmount - iBufPos;
125 | int readCount = 0;
126 | if (charsToRead <= bufCharCount)
127 | {
128 | // All characters can be read from the buffer.
129 | for (int i = 0; i < charsToRead; i++)
130 | {
131 | aBuf[aOffset+i] = iBuf[iBufPos++];
132 | }
133 | readCount += charsToRead;
134 | }
135 | else
136 | {
137 | // First read characters from the buffer,
138 | // then read more characters from the Reader.
139 | for (int i = 0; i < bufCharCount; i++)
140 | {
141 | aBuf[aOffset+i] = iBuf[iBufPos++];
142 | }
143 | readCount += bufCharCount;
144 | // Whole buffer has now been read, fill the buffer again.
145 | if (fillBuf() > -1)
146 | {
147 | // Read the remaining characters.
148 | readCount += read(aBuf, aOffset+readCount, aLength-readCount);
149 | }
150 | }
151 | if (readCount <= 0)
152 | {
153 | // Nothing has been read, return -1 to indicate end of stream.
154 | readCount = -1;
155 | }
156 | return readCount;
157 | }
158 |
159 | /**
160 | * @see java.io.BufferedReader#readLine()
161 | */
162 | public String readLine() throws IOException
163 | {
164 | if (!ensureBuf())
165 | {
166 | // End of stream has been reached.
167 | return null;
168 | }
169 | StringBuffer line = new StringBuffer();
170 | while (ensureBuf())
171 | {
172 | if (skipEol())
173 | {
174 | // End of line found.
175 | break;
176 | }
177 | else
178 | {
179 | // Append characters to result line.
180 | line.append(iBuf[iBufPos++]);
181 | }
182 | }
183 | return line.toString();
184 | }
185 |
186 | /**
187 | * @see java.io.BufferedReader#ready()
188 | */
189 | public boolean ready() throws IOException
190 | {
191 | if (iBufPos < iBufAmount)
192 | {
193 | return true;
194 | }
195 | if (iReader != null)
196 | {
197 | return iReader.ready();
198 | }
199 | return false;
200 | }
201 |
202 | /**
203 | * @see java.io.BufferedReader#skip()
204 | */
205 | public long skip(long aAmountToSkip) throws IOException
206 | {
207 | if (aAmountToSkip < 0)
208 | {
209 | throw new IllegalArgumentException(
210 | "BufferedReader: Cannot skip negative amount of characters");
211 | }
212 | long skipped = 0;
213 | int bufCharCount = iBufAmount - iBufPos;
214 | if (aAmountToSkip <= bufCharCount)
215 | {
216 | // There is enough characters in buffer to skip.
217 | iBufPos += aAmountToSkip;
218 | skipped += aAmountToSkip;
219 | }
220 | else
221 | {
222 | // First skip characters that are available in the buffer,
223 | // then skip characters from the Reader.
224 | iBufPos += bufCharCount;
225 | skipped += bufCharCount;
226 | if (iReader != null)
227 | {
228 | skipped += iReader.skip(aAmountToSkip - skipped);
229 | }
230 | }
231 | return skipped;
232 | }
233 |
234 | /**
235 | * If current read position in the buffer is end of line,
236 | * move position over end of line and return true, otherwise
237 | * return false. Also in the end of stream case this method
238 | * returns true.
239 | */
240 | private boolean skipEol() throws IOException
241 | {
242 | if (!ensureBuf())
243 | {
244 | // End of stream has been reached.
245 | return true;
246 | }
247 | boolean eolFound = false;
248 | if (iBufAmount > iBufPos && iBuf[iBufPos] == '\r')
249 | {
250 | iBufPos += 1;
251 | eolFound = true;
252 | ensureBuf();
253 | }
254 | if (iBufAmount > iBufPos && iBuf[iBufPos] == '\n')
255 | {
256 | iBufPos += 1;
257 | eolFound = true;
258 | }
259 | return eolFound;
260 | }
261 |
262 | /**
263 | * Ensures that the buffer has characters to read.
264 | *
265 | * @return True if the buffer has characters to read,
266 | * false if end of stream has been reached.
267 | */
268 | private boolean ensureBuf() throws IOException
269 | {
270 | boolean result = true;
271 | if (iBufPos >= iBufAmount)
272 | {
273 | if (fillBuf() == -1)
274 | {
275 | result = false;
276 | }
277 | }
278 | return result;
279 | }
280 |
281 | /**
282 | * Fills the buffer from the Reader and resets the buffer counters.
283 | *
284 | * @return The number of characters read, or -1 if the end of
285 | * stream has been reached.
286 | */
287 | private int fillBuf() throws IOException
288 | {
289 | if (iReader == null)
290 | {
291 | return -1;
292 | }
293 | // Fill the buffer.
294 | int readCount = iReader.read(iBuf);
295 | if (readCount > -1)
296 | {
297 | // Reset the buffer counters only if reading succeeded.
298 | iBufAmount = readCount;
299 | iBufPos = 0;
300 | }
301 | return readCount;
302 | }
303 | }
304 |
--------------------------------------------------------------------------------
/src/cc/nnproject/json/JSON.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2021-2025 Arman Jussupgaliyev
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 | package cc.nnproject.json;
23 |
24 | import java.io.IOException;
25 | import java.io.OutputStream;
26 | import java.util.Hashtable;
27 | import java.util.Vector;
28 |
29 | /**
30 | * JSON Library compatible with CLDC 1.1 & JDK 1.1
31 | * Usage:
JSONObject obj = JSON.getObject(str);
-optimizations !code/simplification/object
33 | * @author Shinovon
34 | * @version 2.4
35 | */
36 | public final class JSON {
37 |
38 | // parse all nested elements once
39 | static final boolean parse_members = false;
40 |
41 | // identation for formatting
42 | static final String FORMAT_TAB = " ";
43 |
44 | // used internally for storing nulls, get methods must return real null
45 | public static final Object json_null = new Object();
46 |
47 | public static final Boolean TRUE = new Boolean(true);
48 | public static final Boolean FALSE = new Boolean(false);
49 |
50 | public static AbstractJSON get(String text) throws JSONException {
51 | if (text == null || text.length() <= 1)
52 | throw new JSONException("Empty text");
53 | char c = text.charAt(0);
54 | if (c != '{' && c != '[')
55 | throw new JSONException("Not JSON object or array");
56 | return (AbstractJSON) parseJSON(text.trim());
57 | }
58 |
59 | public static JSONObject getObject(String text) throws JSONException {
60 | if (text == null || text.length() <= 1)
61 | throw new JSONException("Empty text");
62 | if (text.charAt(0) != '{')
63 | throw new JSONException("Not JSON object");
64 | return (JSONObject) parseJSON(text.trim());
65 | }
66 |
67 | public static JSONArray getArray(String text) throws JSONException {
68 | if (text == null || text.length() <= 1)
69 | throw new JSONException("Empty text");
70 | if (text.charAt(0) != '[')
71 | throw new JSONException("Not JSON array");
72 | return (JSONArray) parseJSON(text.trim());
73 | }
74 |
75 | static Object getJSON(Object obj) throws JSONException {
76 | if (obj instanceof Hashtable) {
77 | return new JSONObject((Hashtable) obj);
78 | }
79 | if (obj instanceof Vector) {
80 | return new JSONArray((Vector) obj);
81 | }
82 | if (obj == null) {
83 | return json_null;
84 | }
85 | return obj;
86 | }
87 |
88 | static Object parseJSON(String str) throws JSONException {
89 | char first = str.charAt(0);
90 | int length;
91 | char last = str.charAt(length = str.length() - 1);
92 | if (last <= ' ')
93 | last = (str = str.trim()).charAt(length = str.length() - 1);
94 | switch (first) {
95 | case '"': { // string
96 | if (last != '"')
97 | throw new JSONException("Unexpected end of text");
98 | if (str.indexOf('\\') != -1) {
99 | char[] chars = str.substring(1, length).toCharArray();
100 | str = null;
101 | int l = chars.length;
102 | StringBuffer sb = new StringBuffer();
103 | int i = 0;
104 | // parse escaped chars in string
105 | loop: {
106 | while (i < l) {
107 | char c = chars[i];
108 | switch (c) {
109 | case '\\': {
110 | next: {
111 | replace: {
112 | if (l < i + 1) {
113 | sb.append(c);
114 | break loop;
115 | }
116 | char c1 = chars[i + 1];
117 | switch (c1) {
118 | case 'u':
119 | i+=2;
120 | sb.append((char) Integer.parseInt(
121 | new String(new char[] {chars[i++], chars[i++], chars[i++], chars[i++]}),
122 | 16));
123 | break replace;
124 | case 'x':
125 | i+=2;
126 | sb.append((char) Integer.parseInt(
127 | new String(new char[] {chars[i++], chars[i++]}),
128 | 16));
129 | break replace;
130 | case 'n':
131 | sb.append('\n');
132 | i+=2;
133 | break replace;
134 | case 'r':
135 | sb.append('\r');
136 | i+=2;
137 | break replace;
138 | case 't':
139 | sb.append('\t');
140 | i+=2;
141 | break replace;
142 | case 'f':
143 | sb.append('\f');
144 | i+=2;
145 | break replace;
146 | case 'b':
147 | sb.append('\b');
148 | i+=2;
149 | break replace;
150 | case '\"':
151 | case '\'':
152 | case '\\':
153 | case '/':
154 | i+=2;
155 | sb.append((char) c1);
156 | break replace;
157 | default:
158 | break next;
159 | }
160 | }
161 | break;
162 | }
163 | sb.append(c);
164 | i++;
165 | break;
166 | }
167 | default:
168 | sb.append(c);
169 | i++;
170 | }
171 | }
172 | }
173 | str = sb.toString();
174 | sb = null;
175 | return str;
176 | }
177 | return str.substring(1, length);
178 | }
179 | case '{': // JSON object or array
180 | case '[': {
181 | boolean object = first == '{';
182 | if (object ? last != '}' : last != ']')
183 | throw new JSONException("Unexpected end of text");
184 | int brackets = 0;
185 | int i = 1;
186 | char nextDelimiter = object ? ':' : ',';
187 | boolean escape = false;
188 | String key = null;
189 | Object res = object ? (Object) new JSONObject() : (Object) new JSONArray();
190 |
191 | for (int splIndex; i < length; i = splIndex + 1) {
192 | // skip all spaces
193 | for (; i < length - 1 && str.charAt(i) <= ' '; i++);
194 |
195 | splIndex = i;
196 | boolean quote = false;
197 | for (; splIndex < length && (quote || brackets > 0 || str.charAt(splIndex) != nextDelimiter); splIndex++) {
198 | char c = str.charAt(splIndex);
199 | if (!escape) {
200 | if (c == '\\') {
201 | escape = true;
202 | } else if (c == '"') {
203 | quote = !quote;
204 | }
205 | } else escape = false;
206 |
207 | if (!quote) {
208 | if (c == '{' || c == '[') {
209 | brackets++;
210 | } else if (c == '}' || c == ']') {
211 | brackets--;
212 | }
213 | }
214 | }
215 |
216 | // fail if unclosed quotes or brackets left
217 | if (quote || brackets > 0) {
218 | throw new JSONException("Corrupted JSON");
219 | }
220 |
221 | if (object && key == null) {
222 | key = str.substring(i, splIndex);
223 | key = key.substring(1, key.length() - 1);
224 | nextDelimiter = ',';
225 | } else {
226 | Object value = str.substring(i, splIndex).trim();
227 | // don't check length because if value is empty, then exception is going to be thrown anyway
228 | char c = ((String) value).charAt(0);
229 | // leave JSONString as value to parse it later, if its object or array and nested parsing is disabled
230 | value = parse_members || (c != '{' && c != '[') ?
231 | parseJSON((String) value) : new String[] {(String) value};
232 | if (object) {
233 | ((JSONObject) res)._put(key, value);
234 | key = null;
235 | nextDelimiter = ':';
236 | } else if (splIndex > i) {
237 | ((JSONArray) res).addElement(value);
238 | }
239 | }
240 | }
241 | return res;
242 | }
243 | case 'n': // null
244 | return json_null;
245 | case 't': // true
246 | return TRUE;
247 | case 'f': // false
248 | return FALSE;
249 | default: // number
250 | if ((first >= '0' && first <= '9') || first == '-') {
251 | try {
252 | // hex
253 | if (length > 1 && first == '0' && str.charAt(1) == 'x') {
254 | if (length > 9) // str.length() > 10
255 | return new Long(Long.parseLong(str.substring(2), 16));
256 | return new Integer(Integer.parseInt(str.substring(2), 16));
257 | }
258 | // decimal
259 | if (str.indexOf('.') != -1 || str.indexOf('E') != -1 || "-0".equals(str))
260 | return new Double(Double.parseDouble(str));
261 | if (first == '-') length--;
262 | if (length > 8) // (str.length() - (str.charAt(0) == '-' ? 1 : 0)) >= 10
263 | return new Long(Long.parseLong(str));
264 | return new Integer(Integer.parseInt(str));
265 | } catch (Exception e) {}
266 | }
267 | throw new JSONException("Couldn't be parsed: " + str);
268 | // return new String[](str);
269 | }
270 | }
271 |
272 | public static boolean isNull(Object obj) {
273 | return obj == json_null || obj == null;
274 | }
275 |
276 | // transforms string for exporting
277 | static String escape_utf8(String s) {
278 | int len = s.length();
279 | StringBuffer sb = new StringBuffer();
280 | int i = 0;
281 | while (i < len) {
282 | char c = s.charAt(i);
283 | switch (c) {
284 | case '"':
285 | case '\\':
286 | sb.append("\\").append(c);
287 | break;
288 | case '\b':
289 | sb.append("\\b");
290 | break;
291 | case '\f':
292 | sb.append("\\f");
293 | break;
294 | case '\n':
295 | sb.append("\\n");
296 | break;
297 | case '\r':
298 | sb.append("\\r");
299 | break;
300 | case '\t':
301 | sb.append("\\t");
302 | break;
303 | default:
304 | if (c < 32 || c > 1103 || (c >= '\u0080' && c < '\u00a0')) {
305 | String u = Integer.toHexString(c);
306 | sb.append("\\u");
307 | for (int z = u.length(); z < 4; z++) {
308 | sb.append('0');
309 | }
310 | sb.append(u);
311 | } else {
312 | sb.append(c);
313 | }
314 | }
315 | i++;
316 | }
317 | return sb.toString();
318 | }
319 |
320 | static double getDouble(Object o) throws JSONException {
321 | try {
322 | if (o instanceof String[])
323 | return Double.parseDouble(((String[]) o)[0]);
324 | if (o instanceof Integer)
325 | return ((Integer) o).intValue();
326 | if (o instanceof Long)
327 | return ((Long) o).longValue();
328 | if (o instanceof Double)
329 | return ((Double) o).doubleValue();
330 | } catch (Throwable e) {}
331 | throw new JSONException("Cast to double failed: " + o);
332 | }
333 |
334 | static int getInt(Object o) throws JSONException {
335 | try {
336 | if (o instanceof String[])
337 | return Integer.parseInt(((String[]) o)[0]);
338 | if (o instanceof Integer)
339 | return ((Integer) o).intValue();
340 | if (o instanceof Long)
341 | return (int) ((Long) o).longValue();
342 | if (o instanceof Double)
343 | return ((Double) o).intValue();
344 | } catch (Throwable e) {}
345 | throw new JSONException("Cast to int failed: " + o);
346 | }
347 |
348 | static long getLong(Object o) throws JSONException {
349 | try {
350 | if (o instanceof String[])
351 | return Long.parseLong(((String[]) o)[0]);
352 | if (o instanceof Integer)
353 | return ((Integer) o).longValue();
354 | if (o instanceof Long)
355 | return ((Long) o).longValue();
356 | if (o instanceof Double)
357 | return ((Double) o).longValue();
358 | } catch (Throwable e) {}
359 | throw new JSONException("Cast to long failed: " + o);
360 | }
361 |
362 | public static void writeString(OutputStream out, String s) throws IOException {
363 | int len = s.length();
364 | for (int i = 0; i < len; ++i) {
365 | char c = s.charAt(i);
366 | switch (c) {
367 | case '"':
368 | case '\\':
369 | out.write((byte) '\\');
370 | out.write((byte) c);
371 | break;
372 | case '\b':
373 | out.write((byte) '\\');
374 | out.write((byte) 'b');
375 | break;
376 | case '\f':
377 | out.write((byte) '\\');
378 | out.write((byte) 'f');
379 | break;
380 | case '\n':
381 | out.write((byte) '\\');
382 | out.write((byte) 'n');
383 | break;
384 | case '\r':
385 | out.write((byte) '\\');
386 | out.write((byte) 'r');
387 | break;
388 | case '\t':
389 | out.write((byte) '\\');
390 | out.write((byte) 't');
391 | break;
392 | default:
393 | if (c < 32 || c > 255) {
394 | out.write((byte) '\\');
395 | out.write((byte) 'u');
396 | String u = Integer.toHexString(c);
397 | for (int z = u.length(); z < 4; z++) {
398 | out.write((byte) '0');
399 | }
400 | out.write(u.getBytes());
401 | } else {
402 | out.write((byte) c);
403 | }
404 | }
405 | }
406 | }
407 |
408 | }
409 |
--------------------------------------------------------------------------------
/src/cc/nnproject/json/JSONArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2021-2025 Arman Jussupgaliyev
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 | package cc.nnproject.json;
23 |
24 | import java.io.IOException;
25 | import java.io.OutputStream;
26 | import java.util.Enumeration;
27 | import java.util.Vector;
28 |
29 | public class JSONArray extends AbstractJSON {
30 |
31 | protected Object[] elements;
32 | protected int count;
33 |
34 | public JSONArray() {
35 | elements = new Object[10];
36 | }
37 |
38 | public JSONArray(int size) {
39 | elements = new Object[size];
40 | }
41 |
42 | /**
43 | * @deprecated Doesn't adapt nested elements
44 | */
45 | public JSONArray(Vector vector) {
46 | elements = new Object[count = vector.size()];
47 | vector.copyInto(elements);
48 | }
49 |
50 | /**
51 | * @deprecated Compatibility with org.json
52 | */
53 | public JSONArray(String str) {
54 | JSONArray tmp = JSON.getArray(str); // FIXME
55 | elements = tmp.elements;
56 | count = tmp.count;
57 | }
58 |
59 | public Object get(int index) throws JSONException {
60 | if (index < 0 || index >= count) {
61 | throw new JSONException("Index out of bounds: " + index);
62 | }
63 | try {
64 | Object o = elements[index];
65 | if (o instanceof String[])
66 | o = elements[index] = JSON.parseJSON(((String[]) o)[0]);
67 | if (o == JSON.json_null)
68 | return null;
69 | return o;
70 | } catch (Exception e) {
71 | }
72 | throw new JSONException("No value at " + index);
73 | }
74 |
75 | // unused methods should be removed by proguard shrinking
76 |
77 | public Object get(int index, Object def) {
78 | try {
79 | return get(index);
80 | } catch (Exception e) {
81 | return def;
82 | }
83 | }
84 |
85 | public Object getNullable(int index) {
86 | return get(index, null);
87 | }
88 |
89 | public String getString(int index) throws JSONException {
90 | Object o = get(index);
91 | if (o == null || o instanceof String)
92 | return (String) o;
93 | return String.valueOf(o);
94 | }
95 |
96 | public String getString(int index, String def) {
97 | try {
98 | Object o = get(index);
99 | if (o == null || o instanceof String)
100 | return (String) o;
101 | return String.valueOf(o);
102 | } catch (Exception e) {
103 | return def;
104 | }
105 | }
106 |
107 | public String getNullableString(int index) {
108 | return getString(index, null);
109 | }
110 |
111 | public JSONObject getObject(int index) throws JSONException {
112 | try {
113 | return (JSONObject) get(index);
114 | } catch (ClassCastException e) {
115 | throw new JSONException("Not object at " + index);
116 | }
117 | }
118 |
119 | public JSONObject getObject(int index, JSONObject def) {
120 | try {
121 | return getObject(index);
122 | } catch (Exception e) {
123 | }
124 | return def;
125 | }
126 |
127 | public JSONObject getNullableObject(int index) {
128 | return getObject(index, null);
129 | }
130 |
131 | public JSONArray getArray(int index) throws JSONException {
132 | try {
133 | return (JSONArray) get(index);
134 | } catch (ClassCastException e) {
135 | throw new JSONException("Not array at " + index);
136 | }
137 | }
138 |
139 | public JSONArray getArray(int index, JSONArray def) {
140 | try {
141 | return getArray(index);
142 | } catch (Exception e) {
143 | }
144 | return def;
145 | }
146 |
147 | public JSONArray getNullableArray(int index) {
148 | return getArray(index, null);
149 | }
150 |
151 | public int getInt(int index) throws JSONException {
152 | return JSON.getInt(get(index));
153 | }
154 |
155 | public int getInt(int index, int def) {
156 | try {
157 | return getInt(index);
158 | } catch (Exception e) {
159 | return def;
160 | }
161 | }
162 |
163 | public long getLong(int index) throws JSONException {
164 | return JSON.getLong(get(index));
165 | }
166 |
167 | public long getLong(int index, long def) {
168 | try {
169 | return getLong(index);
170 | } catch (Exception e) {
171 | return def;
172 | }
173 | }
174 |
175 | public double getDouble(int index) throws JSONException {
176 | return JSON.getDouble(get(index));
177 | }
178 |
179 | public double getDouble(int index, double def) {
180 | try {
181 | return getDouble(index);
182 | } catch (Exception e) {
183 | return def;
184 | }
185 | }
186 |
187 | public boolean getBoolean(int index) throws JSONException {
188 | Object o = get(index);
189 | if (o == JSON.TRUE) return true;
190 | if (o == JSON.FALSE) return false;
191 | if (o instanceof Boolean) return ((Boolean) o).booleanValue();
192 | if (o instanceof String) {
193 | String s = (String) o;
194 | s = s.toLowerCase();
195 | if (s.equals("true")) return true;
196 | if (s.equals("false")) return false;
197 | }
198 | throw new JSONException("Not boolean: " + o + " (" + index + ")");
199 | }
200 |
201 | public boolean getBoolean(int index, boolean def) {
202 | try {
203 | return getBoolean(index);
204 | } catch (Exception e) {
205 | return def;
206 | }
207 | }
208 |
209 | public boolean isNull(int index) {
210 | if (index < 0 || index >= count) {
211 | throw new JSONException("Index out of bounds: " + index);
212 | }
213 | return elements[index] == JSON.json_null;
214 | }
215 |
216 | /**
217 | * @deprecated
218 | */
219 | public void add(Object object) {
220 | if (object == this) throw new JSONException();
221 | addElement(JSON.getJSON(object));
222 | }
223 |
224 | public void add(AbstractJSON json) {
225 | if (json == this) throw new JSONException();
226 | addElement(json);
227 | }
228 |
229 | public void add(String s) {
230 | addElement(s);
231 | }
232 |
233 | public void add(int i) {
234 | addElement(new Integer(i));
235 | }
236 |
237 | public void add(long l) {
238 | addElement(new Long(l));
239 | }
240 |
241 | public void add(double d) {
242 | addElement(new Double(d));
243 | }
244 |
245 | public void add(boolean b) {
246 | addElement(new Boolean(b));
247 | }
248 |
249 | /**
250 | * @deprecated
251 | */
252 | public void set(int index, Object object) {
253 | if (object == this) throw new JSONException();
254 | if (index < 0 || index >= count) {
255 | throw new JSONException("Index out of bounds: " + index);
256 | }
257 | elements[index] = JSON.getJSON(object);
258 | }
259 |
260 | public void set(int index, AbstractJSON json) {
261 | if (json == this) throw new JSONException();
262 | if (index < 0 || index >= count) {
263 | throw new JSONException("Index out of bounds: " + index);
264 | }
265 | elements[index] = json;
266 | }
267 |
268 | public void set(int index, String s) {
269 | if (index < 0 || index >= count) {
270 | throw new JSONException("Index out of bounds: " + index);
271 | }
272 | elements[index] = s;
273 | }
274 |
275 | public void set(int index, int i) {
276 | if (index < 0 || index >= count) {
277 | throw new JSONException("Index out of bounds: " + index);
278 | }
279 | elements[index] = new Integer(i);
280 | }
281 |
282 | public void set(int index, long l) {
283 | if (index < 0 || index >= count) {
284 | throw new JSONException("Index out of bounds: " + index);
285 | }
286 | elements[index] = new Long(l);
287 | }
288 |
289 | public void set(int index, double d) {
290 | if (index < 0 || index >= count) {
291 | throw new JSONException("Index out of bounds: " + index);
292 | }
293 | elements[index] = new Double(d);
294 | }
295 |
296 | public void set(int index, boolean b) {
297 | if (index < 0 || index >= count) {
298 | throw new JSONException("Index out of bounds: " + index);
299 | }
300 | elements[index] = new Boolean(b);
301 | }
302 |
303 | /**
304 | * @deprecated
305 | */
306 | public void put(int index, Object object) {
307 | if (object == this) throw new JSONException();
308 | insertElementAt(JSON.getJSON(object), index);
309 | }
310 |
311 | public void put(int index, AbstractJSON json) {
312 | if (json == this) throw new JSONException();
313 | insertElementAt(json, index);
314 | }
315 |
316 | public void put(int index, String s) {
317 | insertElementAt(s, index);
318 | }
319 |
320 | public void put(int index, int i) {
321 | insertElementAt(new Integer(i), index);
322 | }
323 |
324 | public void put(int index, long l) {
325 | insertElementAt(new Long(l), index);
326 | }
327 |
328 | public void put(int index, double d) {
329 | insertElementAt(new Double(d), index);
330 | }
331 |
332 | public void put(int index, boolean b) {
333 | insertElementAt(new Boolean(b), index);
334 | }
335 |
336 | public boolean has(Object object) {
337 | return _indexOf(JSON.getJSON(object), 0) != -1;
338 | }
339 |
340 | public boolean has(int i) {
341 | return _indexOf(new Integer(i), 0) != -1;
342 | }
343 |
344 | public boolean has(long l) {
345 | return _indexOf(new Long(l), 0) != -1;
346 | }
347 |
348 | public boolean has(double d) {
349 | return _indexOf(new Double(d), 0) != -1;
350 | }
351 |
352 | public boolean has(boolean b) {
353 | return _indexOf(new Boolean(b), 0) != -1;
354 | }
355 |
356 | public int indexOf(Object object) {
357 | return _indexOf(JSON.getJSON(object), 0);
358 | }
359 |
360 | public int indexOf(Object object, int index) {
361 | return _indexOf(JSON.getJSON(object), index);
362 | }
363 |
364 | public void clear() {
365 | for (int i = 0; i < count; i++) elements[i] = null;
366 | count = 0;
367 | }
368 |
369 | public boolean remove(Object object) {
370 | int i = _indexOf(JSON.getJSON(object), 0);
371 | if (i == -1) return false;
372 | remove(i);
373 | return true;
374 | }
375 |
376 | public void remove(int index) {
377 | if (index < 0 || index >= count) {
378 | throw new JSONException("Index out of bounds: " + index);
379 | }
380 | count--;
381 | int size = count - index;
382 | if (size > 0)
383 | System.arraycopy(elements, index + 1, elements, index, size);
384 | elements[count] = null;
385 | }
386 |
387 | public int size() {
388 | return count;
389 | }
390 |
391 | public boolean isEmpty() {
392 | return count == 0;
393 | }
394 |
395 | public String toString() {
396 | return build();
397 | }
398 |
399 | public boolean equals(Object obj) {
400 | return this == obj || super.equals(obj) || similar(obj);
401 | }
402 |
403 | public boolean similar(Object obj) {
404 | if (!(obj instanceof JSONArray)) {
405 | return false;
406 | }
407 | int size = count;
408 | if (size != ((JSONArray)obj).count) {
409 | return false;
410 | }
411 | for (int i = 0; i < size; i++) {
412 | Object a = get(i);
413 | Object b = ((JSONArray)obj).get(i);
414 | if (a == b) {
415 | continue;
416 | }
417 | if (a == null) {
418 | return false;
419 | }
420 | if (a instanceof AbstractJSON) {
421 | if (!((AbstractJSON)a).similar(b)) {
422 | return false;
423 | }
424 | } else if (!a.equals(b)) {
425 | return false;
426 | }
427 | }
428 | return true;
429 | }
430 |
431 | public String build() {
432 | int size = count;
433 | if (size == 0)
434 | return "[]";
435 | StringBuffer s = new StringBuffer("[");
436 | int i = 0;
437 | while (i < size) {
438 | Object v = elements[i];
439 | if (v instanceof AbstractJSON) {
440 | s.append(((AbstractJSON) v).build());
441 | } else if (v instanceof String) {
442 | s.append("\"").append(JSON.escape_utf8((String) v)).append("\"");
443 | } else if (v instanceof String[]) {
444 | s.append(((String[]) v)[0]);
445 | } else if (v == JSON.json_null) {
446 | s.append((String) null);
447 | } else {
448 | s.append(String.valueOf(v));
449 | }
450 | i++;
451 | if (i < size) {
452 | s.append(",");
453 | }
454 | }
455 | s.append("]");
456 | return s.toString();
457 | }
458 |
459 | protected String format(int l) {
460 | int size = count;
461 | if (size == 0)
462 | return "[]";
463 | String t = "";
464 | for (int i = 0; i < l; i++) {
465 | t = t.concat(JSON.FORMAT_TAB);
466 | }
467 | String t2 = t.concat(JSON.FORMAT_TAB);
468 | StringBuffer s = new StringBuffer("[\n");
469 | s.append(t2);
470 | int i = 0;
471 | while (i < size) {
472 | Object v = elements[i];
473 | if (v instanceof String[]) {
474 | v = elements[i] = JSON.parseJSON(((String[]) v)[0]);
475 | }
476 | if (v instanceof AbstractJSON) {
477 | s.append(((AbstractJSON) v).format(l + 1));
478 | } else if (v instanceof String) {
479 | s.append("\"").append(JSON.escape_utf8((String) v)).append("\"");
480 | } else if (v == JSON.json_null) {
481 | s.append((String) null);
482 | } else {
483 | s.append(v);
484 | }
485 | i++;
486 | if (i < size) {
487 | s.append(",\n").append(t2);
488 | }
489 | }
490 | if (l > 0) {
491 | s.append("\n").append(t).append("]");
492 | } else {
493 | s.append("\n]");
494 | }
495 | return s.toString();
496 | }
497 |
498 | public void write(OutputStream out) throws IOException {
499 | int size = count;
500 | out.write((byte) '[');
501 | if (size == 0) {
502 | out.write((byte) ']');
503 | return;
504 | }
505 | int i = 0;
506 | while (i < size) {
507 | Object v = elements[i];
508 | if (v instanceof JSONObject) {
509 | ((JSONObject) v).write(out);
510 | } else if (v instanceof JSONArray) {
511 | ((JSONArray) v).write(out);
512 | } else if (v instanceof String) {
513 | out.write((byte) '"');
514 | JSON.writeString(out, (String) v);
515 | out.write((byte) '"');
516 | } else if (v instanceof String[]) {
517 | out.write((((String[]) v)[0]).getBytes("UTF-8"));
518 | } else if (v == JSON.json_null) {
519 | out.write((byte) 'n');
520 | out.write((byte) 'u');
521 | out.write((byte) 'l');
522 | out.write((byte) 'l');
523 | } else {
524 | out.write(String.valueOf(v).getBytes("UTF-8"));
525 | }
526 | i++;
527 | if (i < size) {
528 | out.write((byte) ',');
529 | }
530 | }
531 | out.write((byte) '}');
532 | }
533 |
534 | public Enumeration elements() {
535 | return new Enumeration() {
536 | int i = 0;
537 |
538 | public boolean hasMoreElements() {
539 | return i < count;
540 | }
541 |
542 | public Object nextElement() {
543 | Object o = elements[i];
544 | if (o instanceof String[])
545 | o = elements[i] = JSON.parseJSON(((String[]) o)[0]);
546 | i++;
547 | return o == JSON.json_null ? null : o;
548 | }
549 | };
550 | }
551 |
552 | public void copyInto(Object[] arr) {
553 | copyInto(arr, 0, arr.length);
554 | }
555 |
556 | public void copyInto(Object[] arr, int offset, int length) {
557 | int i = offset;
558 | int j = 0;
559 | while(i < arr.length && j < length && j < size()) {
560 | arr[i++] = get(j++);
561 | }
562 | }
563 |
564 | public Vector toVector() {
565 | int size = count;
566 | Vector copy = new Vector(size);
567 | for (int i = 0; i < size; i++) {
568 | Object o = elements[i];
569 | if (o instanceof String[])
570 | o = elements[i] = JSON.parseJSON(((String[]) o)[0]);
571 | if (o instanceof JSONObject) {
572 | o = ((JSONObject) o).toTable();
573 | } else if (o instanceof JSONArray) {
574 | o = ((JSONArray) o).toVector();
575 | }
576 | copy.addElement(o);
577 | }
578 | return copy;
579 | }
580 |
581 | void addElement(Object object) {
582 | if (count == elements.length) grow();
583 | elements[count++] = object;
584 | }
585 |
586 | private void insertElementAt(Object object, int index) {
587 | if (index < 0 || index > count) {
588 | throw new JSONException("Index out of bounds: " + index);
589 | }
590 | if (count == elements.length) grow();
591 | int size = count - index;
592 | if (size > 0)
593 | System.arraycopy(elements, index, elements, index + 1, size);
594 | elements[index] = object;
595 | count++;
596 | }
597 |
598 | private int _indexOf(Object object, int start) {
599 | for (int i = start; i < count; i++) {
600 | if (elements[i] instanceof String[])
601 | elements[i] = JSON.parseJSON(((String[]) elements[i])[0]);
602 | if (object.equals(elements[i])) return i;
603 | }
604 | return -1;
605 | }
606 |
607 | private void grow() {
608 | Object[] tmp = new Object[elements.length * 2];
609 | System.arraycopy(elements, 0, tmp, 0, count);
610 | elements = tmp;
611 | }
612 |
613 | }
614 |
--------------------------------------------------------------------------------
/src/cc/nnproject/json/JSONException.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2021-2024 Arman Jussupgaliyev
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 | package cc.nnproject.json;
23 |
24 | public class JSONException extends RuntimeException {
25 |
26 | public JSONException() {
27 | }
28 |
29 | public JSONException(String msg) {
30 | super(msg);
31 | }
32 |
33 | public String toString() {
34 | return getMessage() == null ? "JSONException" : "JSONException: " + getMessage();
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/cc/nnproject/json/JSONObject.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2021-2025 Arman Jussupgaliyev
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 | package cc.nnproject.json;
23 |
24 | import java.io.IOException;
25 | import java.io.OutputStream;
26 | import java.util.Enumeration;
27 | import java.util.Hashtable;
28 |
29 | public class JSONObject extends AbstractJSON {
30 |
31 | protected Hashtable table;
32 |
33 | public JSONObject() {
34 | table = new Hashtable();
35 | }
36 |
37 | /**
38 | * @deprecated Doesn't adapt nested elements
39 | */
40 | public JSONObject(Hashtable table) {
41 | this.table = table;
42 | }
43 |
44 | /**
45 | * @deprecated Compatibility with org.json
46 | */
47 | public JSONObject(String str) {
48 | table = JSON.getObject(str).table; // FIXME
49 | }
50 |
51 | public Object get(String name) throws JSONException {
52 | try {
53 | if (has(name)) {
54 | Object o = table.get(name);
55 | if (o instanceof String[])
56 | table.put(name, o = JSON.parseJSON(((String[]) o)[0]));
57 | if (o == JSON.json_null)
58 | return null;
59 | return o;
60 | }
61 | } catch (JSONException e) {
62 | throw e;
63 | } catch (Exception e) {}
64 | throw new JSONException("No value for name: " + name);
65 | }
66 |
67 | // unused methods should be removed by proguard shrinking
68 |
69 | public Object get(String name, Object def) {
70 | if (!has(name)) return def;
71 | try {
72 | return get(name);
73 | } catch (Exception e) {
74 | return def;
75 | }
76 | }
77 |
78 | public Object getNullable(String name) {
79 | return get(name, null);
80 | }
81 |
82 | public String getString(String name) throws JSONException {
83 | Object o = get(name);
84 | if (o == null || o instanceof String)
85 | return (String) o;
86 | return String.valueOf(o);
87 | }
88 |
89 | public String getString(String name, String def) {
90 | try {
91 | Object o = get(name, def);
92 | if (o == null || o instanceof String)
93 | return (String) o;
94 | return String.valueOf(o);
95 | } catch (Exception e) {
96 | return def;
97 | }
98 | }
99 |
100 | public String getNullableString(String name) {
101 | return getString(name, null);
102 | }
103 |
104 | public JSONObject getObject(String name) throws JSONException {
105 | try {
106 | return (JSONObject) get(name);
107 | } catch (ClassCastException e) {
108 | throw new JSONException("Not object: " + name);
109 | }
110 | }
111 | public JSONObject getObject(String name, JSONObject def) {
112 | if (has(name)) {
113 | try {
114 | return (JSONObject) get(name);
115 | } catch (Exception e) {}
116 | }
117 | return def;
118 | }
119 |
120 | public JSONObject getNullableObject(String name) {
121 | return getObject(name, null);
122 | }
123 |
124 | public JSONArray getArray(String name) throws JSONException {
125 | try {
126 | return (JSONArray) get(name);
127 | } catch (ClassCastException e) {
128 | throw new JSONException("Not array: " + name);
129 | }
130 | }
131 |
132 | public JSONArray getArray(String name, JSONArray def) throws JSONException {
133 | if (has(name)) {
134 | try {
135 | return (JSONArray) get(name);
136 | } catch (Exception e) {
137 | }
138 | }
139 | return def;
140 | }
141 |
142 |
143 | public JSONArray getNullableArray(String name) {
144 | return getArray(name, null);
145 | }
146 |
147 | public int getInt(String name) throws JSONException {
148 | return JSON.getInt(get(name));
149 | }
150 |
151 | public int getInt(String name, int def) {
152 | if (!has(name)) return def;
153 | try {
154 | return getInt(name);
155 | } catch (Exception e) {
156 | return def;
157 | }
158 | }
159 |
160 | public long getLong(String name) throws JSONException {
161 | return JSON.getLong(get(name));
162 | }
163 |
164 | public long getLong(String name, long def) {
165 | if (!has(name)) return def;
166 | try {
167 | return getLong(name);
168 | } catch (Exception e) {
169 | return def;
170 | }
171 | }
172 |
173 | public double getDouble(String name) throws JSONException {
174 | return JSON.getDouble(get(name));
175 | }
176 |
177 | public double getDouble(String name, double def) {
178 | if (!has(name)) return def;
179 | try {
180 | return getDouble(name);
181 | } catch (Exception e) {
182 | return def;
183 | }
184 | }
185 |
186 | public boolean getBoolean(String name) throws JSONException {
187 | Object o = get(name);
188 | if (o == JSON.TRUE) return true;
189 | if (o == JSON.FALSE) return false;
190 | if (o instanceof Boolean) return ((Boolean) o).booleanValue();
191 | if (o instanceof String) {
192 | String s = (String) o;
193 | s = s.toLowerCase();
194 | if (s.equals("true")) return true;
195 | if (s.equals("false")) return false;
196 | }
197 | throw new JSONException("Not boolean: " + o);
198 | }
199 |
200 | public boolean getBoolean(String name, boolean def) {
201 | if (!has(name)) return def;
202 | try {
203 | return getBoolean(name);
204 | } catch (Exception e) {
205 | return def;
206 | }
207 | }
208 |
209 | public boolean isNull(String name) {
210 | if (!has(name))
211 | throw new JSONException("No value for name: " + name);
212 | return table.get(name) == JSON.json_null;
213 | }
214 |
215 | /**
216 | * @deprecated
217 | */
218 | public void put(String name, Object obj) {
219 | table.put(name, JSON.getJSON(obj));
220 | }
221 |
222 | public void put(String name, AbstractJSON json) {
223 | table.put(name, json == null ? JSON.json_null : json);
224 | }
225 |
226 | public void put(String name, String s) {
227 | table.put(name, s == null ? JSON.json_null : s);
228 | }
229 |
230 | public void put(String name, int i) {
231 | table.put(name, new Integer(i));
232 | }
233 |
234 | public void put(String name, long l) {
235 | table.put(name, new Long(l));
236 | }
237 |
238 | public void put(String name, double d) {
239 | table.put(name, new Double(d));
240 | }
241 |
242 | public void put(String name, boolean b) {
243 | table.put(name, new Boolean(b));
244 | }
245 |
246 | public boolean hasValue(Object object) {
247 | return table.contains(JSON.getJSON(object));
248 | }
249 |
250 | // hasKey
251 | public boolean has(String name) {
252 | return table.containsKey(name);
253 | }
254 |
255 | public void clear() {
256 | table.clear();
257 | }
258 |
259 | public void remove(String name) {
260 | table.remove(name);
261 | }
262 |
263 | public int size() {
264 | return table.size();
265 | }
266 |
267 | public boolean isEmpty() {
268 | return table.isEmpty();
269 | }
270 |
271 | public String toString() {
272 | return build();
273 | }
274 |
275 | public boolean equals(Object obj) {
276 | return this == obj || super.equals(obj) || similar(obj);
277 | }
278 |
279 | public boolean similar(Object obj) {
280 | if (!(obj instanceof JSONObject)) {
281 | return false;
282 | }
283 | if (table.equals(((JSONObject) obj).table)) {
284 | return true;
285 | }
286 | int size = size();
287 | if (size != ((JSONObject)obj).size()) {
288 | return false;
289 | }
290 | Enumeration keys = table.keys();
291 | while (keys.hasMoreElements()) {
292 | String key = (String) keys.nextElement();
293 | Object a = get(key);
294 | Object b = ((JSONObject)obj).get(key);
295 | if (a == b) {
296 | continue;
297 | }
298 | if (a == null) {
299 | return false;
300 | }
301 | if (a instanceof AbstractJSON) {
302 | if (!((AbstractJSON)a).similar(b)) {
303 | return false;
304 | }
305 | } else if (!a.equals(b)) {
306 | return false;
307 | }
308 | }
309 | return true;
310 | }
311 |
312 | public String build() {
313 | if (size() == 0)
314 | return "{}";
315 | StringBuffer s = new StringBuffer("{");
316 | Enumeration keys = table.keys();
317 | while (true) {
318 | String k = (String) keys.nextElement();
319 | s.append("\"").append(k).append("\":");
320 | Object v = table.get(k);
321 | if (v instanceof AbstractJSON) {
322 | s.append(((AbstractJSON) v).build());
323 | } else if (v instanceof String) {
324 | s.append("\"").append(JSON.escape_utf8((String) v)).append("\"");
325 | } else if (v instanceof String[]) {
326 | s.append(((String[]) v)[0]);
327 | } else if (v == JSON.json_null) {
328 | s.append((String) null);
329 | } else {
330 | s.append(v);
331 | }
332 | if (!keys.hasMoreElements()) {
333 | break;
334 | }
335 | s.append(",");
336 | }
337 | s.append("}");
338 | return s.toString();
339 | }
340 |
341 | protected String format(int l) {
342 | int size = size();
343 | if (size == 0)
344 | return "{}";
345 | String t = "";
346 | for (int i = 0; i < l; i++) {
347 | t = t.concat(JSON.FORMAT_TAB);
348 | }
349 | String t2 = t.concat(JSON.FORMAT_TAB);
350 | StringBuffer s = new StringBuffer("{\n");
351 | s.append(t2);
352 | Enumeration keys = table.keys();
353 | int i = 0;
354 | while (keys.hasMoreElements()) {
355 | String k = (String) keys.nextElement();
356 | s.append("\"").append(k).append("\": ");
357 | Object v = get(k);
358 | if (v instanceof String[])
359 | table.put(k, v = JSON.parseJSON(((String[]) v)[0]));
360 | if (v instanceof AbstractJSON) {
361 | s.append(((AbstractJSON) v).format(l + 1));
362 | } else if (v instanceof String) {
363 | s.append("\"").append(JSON.escape_utf8((String) v)).append("\"");
364 | } else if (v == JSON.json_null) {
365 | s.append((String) null);
366 | } else {
367 | s.append(v);
368 | }
369 | i++;
370 | if (i < size) {
371 | s.append(",\n").append(t2);
372 | }
373 | }
374 | if (l > 0) {
375 | s.append("\n").append(t).append("}");
376 | } else {
377 | s.append("\n}");
378 | }
379 | return s.toString();
380 | }
381 |
382 | public void write(OutputStream out) throws IOException {
383 | out.write((byte) '{');
384 | if (size() == 0) {
385 | out.write((byte) '}');
386 | return;
387 | }
388 | Enumeration keys = table.keys();
389 | while (true) {
390 | String k = (String) keys.nextElement();
391 | out.write((byte) '"');
392 | JSON.writeString(out, k.toString());
393 | out.write((byte) '"');
394 | out.write((byte) ':');
395 | Object v = table.get(k);
396 | if (v instanceof JSONObject) {
397 | ((JSONObject) v).write(out);
398 | } else if (v instanceof JSONArray) {
399 | ((JSONArray) v).write(out);
400 | } else if (v instanceof String) {
401 | out.write((byte) '"');
402 | JSON.writeString(out, (String) v);
403 | out.write((byte) '"');
404 | } else if (v instanceof String[]) {
405 | out.write((((String[]) v)[0]).getBytes("UTF-8"));
406 | } else if (v == JSON.json_null) {
407 | out.write((byte) 'n');
408 | out.write((byte) 'u');
409 | out.write((byte) 'l');
410 | out.write((byte) 'l');
411 | } else {
412 | out.write(String.valueOf(v).getBytes("UTF-8"));
413 | }
414 | if (!keys.hasMoreElements()) {
415 | break;
416 | }
417 | out.write((byte) ',');
418 | }
419 | out.write((byte) '}');
420 | }
421 |
422 | public Enumeration keys() {
423 | return table.keys();
424 | }
425 |
426 | public JSONArray keysAsArray() {
427 | JSONArray array = new JSONArray(table.size());
428 | Enumeration keys = table.keys();
429 | while (keys.hasMoreElements()) {
430 | array.addElement(keys.nextElement());
431 | }
432 | return array;
433 | }
434 |
435 | /**
436 | * @deprecated Use {@link JSONObject#toTable()} instead
437 | */
438 | public Hashtable getTable() {
439 | return table;
440 | }
441 |
442 | public Hashtable toTable() {
443 | Hashtable copy = new Hashtable(table.size());
444 | Enumeration keys = table.keys();
445 | while (keys.hasMoreElements()) {
446 | String k = (String) keys.nextElement();
447 | Object v = table.get(k);
448 | if (v instanceof String[])
449 | table.put(k, v = JSON.parseJSON(((String[]) v)[0]));
450 | if (v instanceof JSONObject) {
451 | v = ((JSONObject) v).toTable();
452 | } else if (v instanceof JSONArray) {
453 | v = ((JSONArray) v).toVector();
454 | }
455 | copy.put(k, v);
456 | }
457 | return copy;
458 | }
459 |
460 | void _put(String name, Object obj) {
461 | table.put(name, obj);
462 | }
463 |
464 | // TODO: Enumeration elements()
465 |
466 | }
467 |
--------------------------------------------------------------------------------
/src/cc/nnproject/json/JSONStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Arman Jussupgaliyev
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 | package cc.nnproject.json;
23 |
24 | import java.io.IOException;
25 | import java.io.InputStream;
26 | import java.io.InputStreamReader;
27 | import java.io.Reader;
28 |
29 | // Streaming JSON
30 |
31 | public class JSONStream {
32 |
33 | public static String encoding = "UTF-8";
34 | public static boolean buffer = true;
35 |
36 | private Reader reader;
37 | private boolean isObject;
38 | int index;
39 | private boolean eof;
40 | private char prev;
41 | private boolean usePrev;
42 |
43 | private JSONStream() {}
44 |
45 | private void init(InputStream in) throws IOException {
46 | reader = new InputStreamReader(in, "UTF-8");
47 | if (buffer) {
48 | reader = new BufferedReader(reader);
49 | }
50 | }
51 |
52 | // Static functions
53 |
54 | public static JSONStream getStream(InputStream in) throws IOException {
55 | JSONStream json = new JSONStream();
56 | json.init(in);
57 | char c = json.nextTrim();
58 | if (c != '{' && c != '[')
59 | throw new JSONException("getStream: Not json");
60 | json.isObject = c == '{';
61 | json.usePrev = true;
62 | return json;
63 | }
64 |
65 | public static JSONStream getStream(Reader r) throws IOException {
66 | JSONStream json = new JSONStream();
67 | json.reader = r;
68 | char c = json.nextTrim();
69 | if (c != '{' && c != '[')
70 | throw new JSONException("getStream: Not json");
71 | json.isObject = c == '{';
72 | json.usePrev = true;
73 | return json;
74 | }
75 |
76 | public static AbstractJSON getJSON(InputStream in) throws IOException {
77 | JSONStream json = new JSONStream();
78 | try {
79 | json.init(in);
80 | char c = json.nextTrim();
81 | if (c != '[' && c != '{')
82 | throw new JSONException("getJSON: Not json");
83 | if (c == '{')
84 | return json.nextObject(false);
85 | else
86 | return json.nextArray(false);
87 | } finally {
88 | json.close();
89 | }
90 | }
91 |
92 | public static JSONObject getObject(InputStream in) throws IOException {
93 | JSONStream json = new JSONStream();
94 | try {
95 | json.init(in);
96 | char c = json.nextTrim();
97 | if (c != '{') throw new JSONException("getObject: not object");
98 | return json.nextObject(false);
99 | } finally {
100 | json.close();
101 | }
102 | }
103 |
104 | public static JSONArray getArray(InputStream in) throws IOException {
105 | JSONStream json = new JSONStream();
106 | try {
107 | json.init(in);
108 | char c = json.nextTrim();
109 | if (c != '[') throw new JSONException("getArray: not array");
110 | return json.nextArray(false);
111 | } finally {
112 | json.close();
113 | }
114 | }
115 |
116 | // Streaming JSON functions
117 |
118 | public Object nextValue() throws IOException {
119 | char c = nextTrim();
120 | switch (c) {
121 | case '{':
122 | return nextObject(false);
123 | case '[':
124 | return nextArray(false);
125 | case '"':
126 | return nextString(false);
127 | case 't': // true
128 | skip(3);
129 | return JSON.TRUE;
130 | case 'f': // false
131 | skip(4);
132 | return JSON.FALSE;
133 | case 'n': // null
134 | skip(3);
135 | return JSON.json_null;
136 | default:
137 | back();
138 | return nextValue(true);
139 | }
140 | }
141 |
142 | public JSONObject nextObject() throws IOException {
143 | return nextObject(true);
144 | }
145 |
146 | public JSONArray nextArray() throws IOException {
147 | return nextArray(true);
148 | }
149 |
150 | public String nextString() throws IOException {
151 | return nextString(true);
152 | }
153 |
154 | public Object nextNumber() throws IOException {
155 | Object v = nextValue(true);
156 | if (v instanceof String)
157 | throw new JSONException("nextNumber: not number: ".concat(String.valueOf(v)));
158 | return v;
159 | }
160 |
161 | public boolean isObject() {
162 | return isObject;
163 | }
164 |
165 | public boolean isArray() {
166 | return !isObject;
167 | }
168 |
169 | // Search functions
170 |
171 | // Jumps to key in object
172 | // Result is found, if false will skip to the end of object
173 | public boolean jumpToKey(String key) throws IOException {
174 | // if (!isObject)
175 | // throw new JSONException("jumpToKey: not object");
176 |
177 | char c;
178 | // while((c = nextTrim()) != '"' && c != 0);
179 | // back();
180 |
181 | while (true) {
182 | c = nextTrim();
183 | if (c == ',') continue;
184 | if (c != '"')
185 | throw new RuntimeException("JSON: jumpToKey: malformed object at ".concat(Integer.toString(index)));
186 | back();
187 | if (nextString(true).equals(key)) {
188 | // jump to value
189 | if (nextTrim() != ':')
190 | throw new JSONException("jumpToKey: malformed object at ".concat(Integer.toString(index)));
191 | return true;
192 | }
193 | if (nextTrim() != ':')
194 | throw new JSONException("jumpToKey: malformed object at ".concat(Integer.toString(index)));
195 |
196 | // skipValue();
197 | c = nextTrim();
198 |
199 | switch (c) {
200 | case '{':
201 | skipObject();
202 | break;
203 | case '[':
204 | skipArray();
205 | break;
206 | case '"':
207 | skipString();
208 | break;
209 | case 0:
210 | return false;
211 | default:
212 | while ((c = next()) != 0 && c != ',' && c != '}');
213 | back();
214 | break;
215 | }
216 |
217 | c = nextTrim();
218 | if (c == ',') {
219 | continue;
220 | }
221 | if (c == '}')
222 | return false;
223 | throw new JSONException("jumpToKey: malformed object at ".concat(Integer.toString(index)));
224 | }
225 | }
226 |
227 | // Skip N elements in array
228 | // If param is less than 1 or bigger than left elements count, will skip to the end of array
229 | // Result is success
230 | public boolean skipArrayElements(int count) throws IOException {
231 | while (true) {
232 | char c = nextTrim();
233 | switch (c) {
234 | case ']':
235 | return false;
236 | case '{':
237 | skipObject();
238 | break;
239 | case '[':
240 | skipArray();
241 | break;
242 | case '"':
243 | skipString();
244 | break;
245 | case 0:
246 | return false;
247 | default:
248 | while ((c = next()) != 0 && c != ',' && c != ']');
249 | back();
250 | break;
251 | }
252 | c = nextTrim();
253 | if (c == ',') {
254 | if (--count == 0)
255 | return true;
256 | continue;
257 | }
258 | return false;
259 | }
260 | }
261 |
262 | // public boolean jumpToKeyGlobal(String key) throws IOException {
263 | // char c = 0;
264 | // boolean p = false;
265 | // boolean q = false;
266 | // boolean e = false;
267 | // while(true) {
268 | // if (p) {
269 | // p = false;
270 | // } else c = next();
271 | // if (c == 0) return false;
272 | // if (!e) {
273 | // if (c == '\\') e = true;
274 | // else if (c == '"') q = !q;
275 | // } else e = false;
276 | // if (!q)
277 | // if (c == '{' || c == ',') {
278 | // if ((c = next()) == '\"') {
279 | // back();
280 | // String s = nextString();
281 | // if (nextTrim() != ':')
282 | // throw new JSONException("jumpToKey: malformed object at ".concat(Integer.toString(index)));
283 | // if (key.equals(s)) return true;
284 | // } else p = true;
285 | // }
286 | // }
287 | // }
288 |
289 | //
290 |
291 | public void skipValue() throws IOException {
292 | char c = nextTrim();
293 | switch (c) {
294 | case '{':
295 | skipObject();
296 | break;
297 | case '[':
298 | skipArray();
299 | break;
300 | case '"':
301 | skipString();
302 | break;
303 | case 0:
304 | return;
305 | default:
306 | while ((c = next()) != 0 && c != ',' && c != ':' && c != '}' && c != ']');
307 | back();
308 | break;
309 | }
310 | }
311 |
312 | // Basic reader functions
313 |
314 | public char next() throws IOException {
315 | if (usePrev) {
316 | usePrev = false;
317 | index++;
318 | return prev;
319 | }
320 | // if (eof) return 0;
321 | int r = reader.read();
322 | if (r <= 0) {
323 | eof = true;
324 | return 0;
325 | }
326 | index++;
327 | return prev = (char) r;
328 | }
329 |
330 | public char nextTrim() throws IOException {
331 | char c;
332 | while ((c = next()) <= ' ' && c != 0);
333 | return c;
334 | }
335 |
336 | public void skip(int n) throws IOException {
337 | if (usePrev) {
338 | usePrev = false;
339 | n--;
340 | }
341 | index += n;
342 | reader.skip(n);
343 | }
344 |
345 | public void back() {
346 | if (usePrev || index <= 0) throw new JSONException("back");
347 | usePrev = true;
348 | index--;
349 | }
350 |
351 | public boolean end() {
352 | return eof;
353 | }
354 |
355 | public void expectNext(char c) throws IOException {
356 | char n;
357 | if ((n = next()) != c)
358 | throw new JSONException("Expected '" + c + "', but got '" + n + "' at " + (index-1));
359 | }
360 |
361 | public void expectNextTrim(char c) throws IOException {
362 | char n;
363 | if ((n = nextTrim()) != c)
364 | throw new JSONException("Expected '" + c + "', but got '" + n + "' at " + (index-1));
365 | }
366 |
367 | /**
368 | * @deprecated mark is probably not supported, since target is CLDC
369 | */
370 | public void reset() throws IOException {
371 | index = prev = 0;
372 | usePrev = false;
373 | reader.reset();
374 | }
375 |
376 | public void reset(InputStream is) throws IOException {
377 | try {
378 | close();
379 | } catch (IOException e) {}
380 | index = prev = 0;
381 | usePrev = false;
382 | init(is);
383 | }
384 |
385 | public void close() throws IOException {
386 | reader.close();
387 | }
388 |
389 | //
390 |
391 | private JSONObject nextObject(boolean check) throws IOException {
392 | if (check && nextTrim() != '{') {
393 | back();
394 | throw new JSONException("nextObject: not object at ".concat(Integer.toString(index)));
395 | }
396 | JSONObject r = new JSONObject();
397 | object: {
398 | while (true) {
399 | char c = nextTrim();
400 | if (c == '}') break object;
401 | back();
402 | String key = nextString(true);
403 | if (nextTrim() != ':')
404 | throw new JSONException("nextObject: malformed object at ".concat(Integer.toString(index)));
405 | Object val = null;
406 | c = nextTrim();
407 | switch (c) {
408 | case '}':
409 | break object;
410 | case '{':
411 | val = nextObject(false);
412 | break;
413 | case '[':
414 | val = nextArray(false);
415 | break;
416 | case '"':
417 | val = nextString(false);
418 | break;
419 | case 'n': // null
420 | skip(3);
421 | val = JSON.json_null;
422 | break;
423 | case 't': // true
424 | skip(3);
425 | val = JSON.TRUE;
426 | break;
427 | case 'f': // false
428 | skip(4);
429 | val = JSON.FALSE;
430 | break;
431 | default:
432 | back();
433 | val = nextValue(true);
434 | break;
435 | }
436 | r.put(key, val);
437 | c = nextTrim();
438 | if (c == ',') {
439 | continue;
440 | }
441 | if (c == '}') break;
442 | throw new JSONException("nextObject: malformed object at ".concat(Integer.toString(index)));
443 | }
444 | }
445 | if (eof)
446 | throw new IOException("nextObject: Unexpected end");
447 | return r;
448 | }
449 |
450 | private JSONArray nextArray(boolean check) throws IOException {
451 | if (check && nextTrim() != '[') {
452 | back();
453 | throw new JSONException("nextArray: not array at ".concat(Integer.toString(index)));
454 | }
455 | JSONArray r = new JSONArray();
456 | array: {
457 | while (true) {
458 | Object val = null;
459 | char c = nextTrim();
460 | switch (c) {
461 | case ']':
462 | break array;
463 | case '{':
464 | val = nextObject(false);
465 | break;
466 | case '[':
467 | val = nextArray(false);
468 | break;
469 | case '"':
470 | val = nextString(false);
471 | break;
472 | case 'n': // null
473 | skip(3);
474 | val = JSON.json_null;
475 | break;
476 | case 't': // true
477 | skip(3);
478 | val = JSON.TRUE;
479 | break;
480 | case 'f': // false
481 | skip(4);
482 | val = JSON.FALSE;
483 | break;
484 | default:
485 | back();
486 | val = nextValue(true);
487 | break;
488 | }
489 | r.addElement(val);
490 | c = nextTrim();
491 | if (c == ',') {
492 | continue;
493 | }
494 | if (c == ']') break;
495 | throw new JSONException("nextArray: malformed array at ".concat(Integer.toString(index)));
496 | }
497 | }
498 | if (eof)
499 | throw new IOException("nextArray: Unexpected end");
500 | return r;
501 | }
502 |
503 | private String nextString(boolean check) throws IOException {
504 | if (check && nextTrim() != '"') {
505 | back();
506 | throw new JSONException("nextString: not string at ".concat(Integer.toString(index)));
507 | }
508 | StringBuffer sb = new StringBuffer();
509 | char l = 0;
510 | while (true) {
511 | char c = next();
512 | if (c == '\\' && l != '\\') {
513 | l = c;
514 | continue;
515 | }
516 | if (l == '\\') {
517 | if (c == 'u') {
518 | char[] chars = new char[4];
519 | chars[0] = next();
520 | chars[1] = next();
521 | chars[2] = next();
522 | chars[3] = next();
523 | sb.append(l = (char) Integer.parseInt(new String(chars), 16));
524 | continue;
525 | }
526 | if (c == 'n') {
527 | sb.append(l = '\n');
528 | continue;
529 | }
530 | if (c == 'r') {
531 | sb.append(l = '\r');
532 | continue;
533 | }
534 | if (c == 't') {
535 | sb.append(l = '\t');
536 | continue;
537 | }
538 | if (c == 'f') {
539 | sb.append(l = '\f');
540 | continue;
541 | }
542 | if (c == 'b') {
543 | sb.append(l = '\b');
544 | continue;
545 | }
546 | }
547 | if (c == 0 || (l != '\\' && c == '"')) break;
548 | sb.append(c);
549 | l = c;
550 | }
551 | if (eof)
552 | throw new IOException("nextString: Unexpected end");
553 | return sb.toString();
554 | }
555 |
556 | private void skipObject() throws IOException {
557 | while (true) {
558 | if (nextTrim() != '"')
559 | throw new JSONException("skipObject: malformed object at ".concat(Integer.toString(index)));
560 | skipString();
561 | if (nextTrim() != ':')
562 | throw new JSONException("skipObject: malformed object at ".concat(Integer.toString(index)));
563 | char c = nextTrim();
564 | switch (c) {
565 | case '}':
566 | return;
567 | case '{':
568 | skipObject();
569 | break;
570 | case '[':
571 | skipArray();
572 | break;
573 | case '"':
574 | skipString();
575 | break;
576 | case 0:
577 | return;
578 | default:
579 | while ((c = next()) != 0 && c != ',' && c != ':' && c != '}');
580 | back();
581 | break;
582 | }
583 | c = nextTrim();
584 | if (c == ',') {
585 | continue;
586 | }
587 | if (c == '}') return;
588 | throw new JSONException("skipObject: malformed object at ".concat(Integer.toString(index)));
589 | }
590 | }
591 |
592 | private void skipArray() throws IOException {
593 | while (true) {
594 | char c = nextTrim();
595 | switch (c) {
596 | case ']':
597 | return;
598 | case '{':
599 | skipObject();
600 | break;
601 | case '[':
602 | skipArray();
603 | break;
604 | case '"':
605 | skipString();
606 | break;
607 | case 0:
608 | return;
609 | default:
610 | while ((c = next()) != 0 && c != ',' && c != ']');
611 | back();
612 | break;
613 | }
614 | c = nextTrim();
615 | if (c == ',') {
616 | continue;
617 | }
618 | return;
619 | }
620 | }
621 |
622 | private void skipString() throws IOException {
623 | char l = 0;
624 | while (true) {
625 | char c = next();
626 | if (c == 0 || (l != '\\' && c == '"')) break;
627 | l = c;
628 | }
629 | }
630 |
631 | private Object nextValue(boolean convertToNumber) throws IOException {
632 | StringBuffer sb = new StringBuffer();
633 | while (true) {
634 | char c = next();
635 | if (c == 0) throw new JSONException("nextValue: Unexpected end");
636 | if (c == ',' || c == ']' || c == '}' || c == ':' || c <= ' ') {
637 | back();
638 | break;
639 | }
640 | sb.append(c);
641 | }
642 | String str = sb.toString();
643 | if (convertToNumber) {
644 | char first = str.charAt(0);
645 | int length = str.length();
646 | if ((first >= '0' && first <= '9') || first == '-') {
647 | try {
648 | // hex
649 | if (length > 1 && first == '0' && str.charAt(1) == 'x') {
650 | if (length > 9) // str.length() > 10
651 | return new Long(Long.parseLong(str.substring(2), 16));
652 | return new Integer(Integer.parseInt(str.substring(2), 16));
653 | }
654 | // decimal
655 | if (str.indexOf('.') != -1 || str.indexOf('E') != -1 || "-0".equals(str))
656 | return new Double(Double.parseDouble(str));
657 | if (first == '-') length--;
658 | if (length > 8) // (str.length() - (str.charAt(0) == '-' ? 1 : 0)) >= 10
659 | return new Long(Long.parseLong(str));
660 | return new Integer(Integer.parseInt(str));
661 | } catch (Exception ignored) {}
662 | }
663 | }
664 | return str;
665 | }
666 |
667 | }
668 |
--------------------------------------------------------------------------------