View Javadoc

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.text.ParseException;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.Map;
31  import java.util.NoSuchElementException;
32  
33  /**
34   * A JSONObject is an unordered collection of name/value pairs. Its external
35   * form is a string wrapped in curly braces with colons between the names and
36   * values, and commas between the values and names. The internal form is an
37   * object having get() and opt() methods for accessing the values by name, and
38   * put() methods for adding or replacing values by name. The values can be any
39   * of these types: Boolean, JSONArray, JSONObject, Number, String, or the
40   * JSONObject.NULL object.
41   * <p>
42   * The constructor can convert an external form string into an internal form
43   * Java object. The toString() method creates an external form string.
44   * <p>
45   * A get() method returns a value if one can be found, and throws an exception
46   * if one cannot be found. An opt() method returns a default value instead of
47   * throwing an exception, and so is useful for obtaining optional values.
48   * <p>
49   * The generic get() and opt() methods return an object, which you can cast or
50   * query for type. There are also typed get() and opt() methods that do type
51   * checking and type coersion for you.
52   * <p>
53   * The texts produced by the toString() methods are very strict. The
54   * constructors are more forgiving in the texts they will accept:
55   * <ul>
56   * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
57   * before the closing brace.</li>
58   * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single quote)</small>.</li>
59   * <li>Strings do not need to be quoted at all if they do not begin with a
60   * quote or single quote, and if they do not contain leading or trailing spaces,
61   * and if they do not contain any of these characters:
62   * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
63   * if they are not the reserved words <code>true</code>, <code>false</code>,
64   * or <code>null</code>.</li>
65   * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as
66   * by <code>:</code></li>
67   * <li>Values can be followed by <code>;</code> as well as by <code>,</code></li>
68   * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
69   * <code>0x-</code> <small>(hex)</small> prefix.</li>
70   * <li>Line comments can begin with <code>#</code></li>
71   * </ul>
72   * 
73   * @author JSON.org
74   * @version 1
75   */
76  public class JSONObject {
77  
78  	/**
79  	 * JSONObject.NULL is equivalent to the value that JavaScript calls null,
80  	 * whilst Java's null is equivalent to the value that JavaScript calls
81  	 * undefined.
82  	 */
83  	private static final class Null {
84  
85  		/**
86  		 * Make a Null object.
87  		 */
88  		private Null() {
89  		}
90  
91  		/**
92  		 * There is only intended to be a single instance of the NULL object, so
93  		 * the clone method returns itself.
94  		 * 
95  		 * @return NULL.
96  		 */
97  		protected final Object clone() {
98  			return this;
99  		}
100 
101 		/**
102 		 * A Null object is equal to the null value and to itself.
103 		 * 
104 		 * @param object
105 		 *            An object to test for nullness.
106 		 * @return true if the object parameter is the JSONObject.NULL object or
107 		 *         null.
108 		 */
109 		public boolean equals(Object object) {
110 			return object == null || object == this;
111 		}
112 
113 		/**
114 		 * Get the "null" string value.
115 		 * 
116 		 * @return The string "null".
117 		 */
118 		public String toString() {
119 			return "null";
120 		}
121 	}
122 
123 	/**
124 	 * The hash map where the JSONObject's properties are kept.
125 	 */
126 	private HashMap myHashMap;
127 
128 	/**
129 	 * It is sometimes more convenient and less ambiguous to have a NULL object
130 	 * than to use Java's null value. JSONObject.NULL.equals(null) returns true.
131 	 * JSONObject.NULL.toString() returns "null".
132 	 */
133 	public static final Object NULL = new Null();
134 
135 	/**
136 	 * Construct an empty JSONObject.
137 	 */
138 	public JSONObject() {
139 		myHashMap = new HashMap();
140 	}
141 
142 	/**
143 	 * Construct a JSONObject from a JSONTokener.
144 	 * 
145 	 * @throws ParseException
146 	 *             if there is a syntax error in the source string.
147 	 * @param x
148 	 *            A JSONTokener object containing the source string.
149 	 */
150 	@SuppressWarnings("unchecked")
151 	public JSONObject(JSONTokener x) throws ParseException {
152 		this();
153 		char c;
154 		String key;
155 
156 		if (x.nextClean() != '{') {
157 			throw x.syntaxError("A JSONObject must begin with '{'");
158 		}
159 		while (true) {
160 			c = x.nextClean();
161 			switch (c) {
162 			case 0:
163 				throw x.syntaxError("A JSONObject must end with '}'");
164 			case '}':
165 				return;
166 			default:
167 				x.back();
168 				key = x.nextValue().toString();
169 			}
170 
171 			/*
172 			 * The key is followed by ':'. We will also tolerate '=' or '=>'.
173 			 */
174 
175 			c = x.nextClean();
176 			if (c == '=') {
177 				if (x.next() != '>') {
178 					x.back();
179 				}
180 			} else if (c != ':') {
181 				throw x.syntaxError("Expected a ':' after a key");
182 			}
183 			myHashMap.put(key, x.nextValue());
184 
185 			/*
186 			 * Pairs are separated by ','. We will also tolerate ';'.
187 			 */
188 
189 			switch (x.nextClean()) {
190 			case ';':
191 			case ',':
192 				if (x.nextClean() == '}') {
193 					return;
194 				}
195 				x.back();
196 				break;
197 			case '}':
198 				return;
199 			default:
200 				throw x.syntaxError("Expected a ',' or '}'");
201 			}
202 		}
203 	}
204 
205 	/**
206 	 * Construct a JSONObject from a string.
207 	 * 
208 	 * @exception ParseException
209 	 *                The string must be properly formatted.
210 	 * @param string
211 	 *            A string beginning with <code>{</code>&nbsp;<small>(left
212 	 *            brace)</small> and ending with <code>}</code>&nbsp;<small>(right
213 	 *            brace)</small>.
214 	 */
215 	public JSONObject(String string) throws ParseException {
216 		this(new JSONTokener(string));
217 	}
218 
219 	/**
220 	 * Construct a JSONObject from a Map.
221 	 * 
222 	 * @param map
223 	 *            A map object that can be used to initialize the contents of
224 	 *            the JSONObject.
225 	 */
226 	@SuppressWarnings("unchecked")
227 	public JSONObject(Map map) {
228 		myHashMap = new HashMap(map);
229 	}
230 
231 	/**
232 	 * Accumulate values under a key. It is similar to the put method except
233 	 * that if there is already an object stored under the key then a JSONArray
234 	 * is stored under the key to hold all of the accumulated values. If there
235 	 * is already a JSONArray, then the new value is appended to it. In
236 	 * contrast, the put method replaces the previous value.
237 	 * 
238 	 * @throws NullPointerException
239 	 *             if the key is null
240 	 * @param key
241 	 *            A key string.
242 	 * @param value
243 	 *            An object to be accumulated under the key.
244 	 * @return this.
245 	 */
246 	public JSONObject accumulate(String key, Object value)
247 			throws NullPointerException {
248 		JSONArray a;
249 		Object o = opt(key);
250 		if (o == null) {
251 			put(key, value);
252 		} else if (o instanceof JSONArray) {
253 			a = (JSONArray) o;
254 			a.put(value);
255 		} else {
256 			a = new JSONArray();
257 			a.put(o);
258 			a.put(value);
259 			put(key, a);
260 		}
261 		return this;
262 	}
263 
264 	/**
265 	 * Get the value object associated with a key.
266 	 * 
267 	 * @exception NoSuchElementException
268 	 *                if the key is not found.
269 	 * 
270 	 * @param key
271 	 *            A key string.
272 	 * @return The object associated with the key.
273 	 */
274 	public Object get(String key) throws NoSuchElementException {
275 		Object o = opt(key);
276 		if (o == null) {
277 			throw new NoSuchElementException("JSONObject[" + quote(key)
278 					+ "] not found.");
279 		}
280 		return o;
281 	}
282 
283 	/**
284 	 * Get the boolean value associated with a key.
285 	 * 
286 	 * @exception NoSuchElementException
287 	 *                if the key is not found.
288 	 * @exception ClassCastException
289 	 *                if the value is not a Boolean or the String "true" or
290 	 *                "false".
291 	 * 
292 	 * @param key
293 	 *            A key string.
294 	 * @return The truth.
295 	 */
296 	public boolean getBoolean(String key) throws ClassCastException,
297 			NoSuchElementException {
298 		Object o = get(key);
299 		if (o.equals(Boolean.FALSE)
300 				|| (o instanceof String && ((String) o)
301 						.equalsIgnoreCase("false"))) {
302 			return false;
303 		} else if (o.equals(Boolean.TRUE)
304 				|| (o instanceof String && ((String) o)
305 						.equalsIgnoreCase("true"))) {
306 			return true;
307 		}
308 		throw new ClassCastException("JSONObject[" + quote(key)
309 				+ "] is not a Boolean.");
310 	}
311 
312 	/**
313 	 * Get the double value associated with a key.
314 	 * 
315 	 * @exception NoSuchElementException
316 	 *                if the key is not found or if the value is a Number
317 	 *                object.
318 	 * @exception NumberFormatException
319 	 *                if the value cannot be converted to a number.
320 	 * @param key
321 	 *            A key string.
322 	 * @return The numeric value.
323 	 */
324 	public double getDouble(String key) throws NoSuchElementException,
325 			NumberFormatException {
326 		Object o = get(key);
327 		if (o instanceof Number) {
328 			return ((Number) o).doubleValue();
329 		}
330 		if (o instanceof String) {
331 			return new Double((String) o).doubleValue();
332 		}
333 		throw new NumberFormatException("JSONObject[" + quote(key)
334 				+ "] is not a number.");
335 	}
336 
337 	/**
338 	 * Get the HashMap the holds that contents of the JSONObject.
339 	 * 
340 	 * @return The getHashMap.
341 	 */
342 	HashMap getHashMap() {
343 		return myHashMap;
344 	}
345 
346 	/**
347 	 * Get the int value associated with a key.
348 	 * 
349 	 * @exception NoSuchElementException
350 	 *                if the key is not found
351 	 * @exception NumberFormatException
352 	 *                if the value cannot be converted to a number.
353 	 * 
354 	 * @param key
355 	 *            A key string.
356 	 * @return The integer value.
357 	 */
358 	public int getInt(String key) throws NoSuchElementException,
359 			NumberFormatException {
360 		Object o = get(key);
361 		return o instanceof Number ? ((Number) o).intValue()
362 				: (int) getDouble(key);
363 	}
364 
365 	/**
366 	 * Get the JSONArray value associated with a key.
367 	 * 
368 	 * @exception NoSuchElementException
369 	 *                if the key is not found or if the value is not a
370 	 *                JSONArray.
371 	 * 
372 	 * @param key
373 	 *            A key string.
374 	 * @return A JSONArray which is the value.
375 	 */
376 	public JSONArray getJSONArray(String key) throws NoSuchElementException {
377 		Object o = get(key);
378 		if (o instanceof JSONArray) {
379 			return (JSONArray) o;
380 		}
381 		throw new NoSuchElementException("JSONObject[" + quote(key)
382 				+ "] is not a JSONArray.");
383 	}
384 
385 	/**
386 	 * Get the JSONObject value associated with a key.
387 	 * 
388 	 * @exception NoSuchElementException
389 	 *                if the key is not found or if the value is not a
390 	 *                JSONObject.
391 	 * 
392 	 * @param key
393 	 *            A key string.
394 	 * @return A JSONObject which is the value.
395 	 */
396 	public JSONObject getJSONObject(String key) throws NoSuchElementException {
397 		Object o = get(key);
398 		if (o instanceof JSONObject) {
399 			return (JSONObject) o;
400 		}
401 		throw new NoSuchElementException("JSONObject[" + quote(key)
402 				+ "] is not a JSONObject.");
403 	}
404 
405 	/**
406 	 * Get the string associated with a key.
407 	 * 
408 	 * @exception NoSuchElementException
409 	 *                if the key is not found.
410 	 * 
411 	 * @param key
412 	 *            A key string.
413 	 * @return A string which is the value.
414 	 */
415 	public String getString(String key) throws NoSuchElementException {
416 		return get(key).toString();
417 	}
418 
419 	/**
420 	 * Determine if the JSONObject contains a specific key.
421 	 * 
422 	 * @param key
423 	 *            A key string.
424 	 * @return true if the key exists in the JSONObject.
425 	 */
426 	public boolean has(String key) {
427 		return myHashMap.containsKey(key);
428 	}
429 
430 	/**
431 	 * Determine if the value associated with the key is null or if there is no
432 	 * value.
433 	 * 
434 	 * @param key
435 	 *            A key string.
436 	 * @return true if there is no value associated with the key or if the value
437 	 *         is the JSONObject.NULL object.
438 	 */
439 	public boolean isNull(String key) {
440 		return JSONObject.NULL.equals(opt(key));
441 	}
442 
443 	/**
444 	 * Get an enumeration of the keys of the JSONObject.
445 	 * 
446 	 * @return An iterator of the keys.
447 	 */
448 	public Iterator keys() {
449 		return myHashMap.keySet().iterator();
450 	}
451 
452 	/**
453 	 * Get the number of keys stored in the JSONObject.
454 	 * 
455 	 * @return The number of keys in the JSONObject.
456 	 */
457 	public int length() {
458 		return myHashMap.size();
459 	}
460 
461 	/**
462 	 * Produce a JSONArray containing the names of the elements of this
463 	 * JSONObject.
464 	 * 
465 	 * @return A JSONArray containing the key strings, or null if the JSONObject
466 	 *         is empty.
467 	 */
468 	public JSONArray names() {
469 		JSONArray ja = new JSONArray();
470 		Iterator keys = keys();
471 		while (keys.hasNext()) {
472 			ja.put(keys.next());
473 		}
474 		return ja.length() == 0 ? null : ja;
475 	}
476 
477 	/**
478 	 * Produce a string from a number.
479 	 * 
480 	 * @exception ArithmeticException
481 	 *                JSON can only serialize finite numbers.
482 	 * @param n
483 	 *            A Number
484 	 * @return A String.
485 	 */
486 	static public String numberToString(Number n) throws ArithmeticException {
487 		if ((n instanceof Float && (((Float) n).isInfinite() || ((Float) n)
488 				.isNaN()))
489 				|| (n instanceof Double && (((Double) n).isInfinite() || ((Double) n)
490 						.isNaN()))) {
491 			throw new ArithmeticException(
492 					"JSON can only serialize finite numbers.");
493 		}
494 
495 		// Shave off trailing zeros and decimal point, if possible.
496 
497 		String s = n.toString().toLowerCase();
498 		if (s.indexOf('e') < 0 && s.indexOf('.') > 0) {
499 			while (s.endsWith("0")) {
500 				s = s.substring(0, s.length() - 1);
501 			}
502 			if (s.endsWith(".")) {
503 				s = s.substring(0, s.length() - 1);
504 			}
505 		}
506 		return s;
507 	}
508 
509 	/**
510 	 * Get an optional value associated with a key.
511 	 * 
512 	 * @exception NullPointerException
513 	 *                The key must not be null.
514 	 * @param key
515 	 *            A key string.
516 	 * @return An object which is the value, or null if there is no value.
517 	 */
518 	public Object opt(String key) throws NullPointerException {
519 		if (key == null) {
520 			throw new NullPointerException("Null key");
521 		}
522 		return myHashMap.get(key);
523 	}
524 
525 	/**
526 	 * Get an optional boolean associated with a key. It returns false if there
527 	 * is no such key, or if the value is not Boolean.TRUE or the String "true".
528 	 * 
529 	 * @param key
530 	 *            A key string.
531 	 * @return The truth.
532 	 */
533 	public boolean optBoolean(String key) {
534 		return optBoolean(key, false);
535 	}
536 
537 	/**
538 	 * Get an optional boolean associated with a key. It returns the
539 	 * defaultValue if there is no such key, or if it is not a Boolean or the
540 	 * String "true" or "false" (case insensitive).
541 	 * 
542 	 * @param key
543 	 *            A key string.
544 	 * @param defaultValue
545 	 *            The default.
546 	 * @return The truth.
547 	 */
548 	public boolean optBoolean(String key, boolean defaultValue) {
549 		Object o = opt(key);
550 		if (o != null) {
551 			if (o.equals(Boolean.FALSE)
552 					|| (o instanceof String && ((String) o)
553 							.equalsIgnoreCase("false"))) {
554 				return false;
555 			} else if (o.equals(Boolean.TRUE)
556 					|| (o instanceof String && ((String) o)
557 							.equalsIgnoreCase("true"))) {
558 				return true;
559 			}
560 		}
561 		return defaultValue;
562 	}
563 
564 	/**
565 	 * Get an optional double associated with a key, or NaN if there is no such
566 	 * key or if its value is not a number. If the value is a string, an attempt
567 	 * will be made to evaluate it as a number.
568 	 * 
569 	 * @param key
570 	 *            A string which is the key.
571 	 * @return An object which is the value.
572 	 */
573 	public double optDouble(String key) {
574 		return optDouble(key, Double.NaN);
575 	}
576 
577 	/**
578 	 * Get an optional double associated with a key, or the defaultValue if
579 	 * there is no such key or if its value is not a number. If the value is a
580 	 * string, an attempt will be made to evaluate it as a number.
581 	 * 
582 	 * @param key
583 	 *            A key string.
584 	 * @param defaultValue
585 	 *            The default.
586 	 * @return An object which is the value.
587 	 */
588 	public double optDouble(String key, double defaultValue) {
589 		Object o = opt(key);
590 		if (o != null) {
591 			if (o instanceof Number) {
592 				return ((Number) o).doubleValue();
593 			}
594 			try {
595 				return new Double((String) o).doubleValue();
596 			} catch (Exception e) {
597 			}
598 		}
599 		return defaultValue;
600 	}
601 
602 	/**
603 	 * Get an optional int value associated with a key, or zero if there is no
604 	 * such key or if the value is not a number. If the value is a string, an
605 	 * attempt will be made to evaluate it as a number.
606 	 * 
607 	 * @param key
608 	 *            A key string.
609 	 * @return An object which is the value.
610 	 */
611 	public int optInt(String key) {
612 		return optInt(key, 0);
613 	}
614 
615 	/**
616 	 * Get an optional int value associated with a key, or the default if there
617 	 * is no such key or if the value is not a number. If the value is a string,
618 	 * an attempt will be made to evaluate it as a number.
619 	 * 
620 	 * @param key
621 	 *            A key string.
622 	 * @param defaultValue
623 	 *            The default.
624 	 * @return An object which is the value.
625 	 */
626 	public int optInt(String key, int defaultValue) {
627 		Object o = opt(key);
628 		if (o != null) {
629 			if (o instanceof Number) {
630 				return ((Number) o).intValue();
631 			}
632 			try {
633 				return Integer.parseInt((String) o);
634 			} catch (Exception e) {
635 			}
636 		}
637 		return defaultValue;
638 	}
639 
640 	/**
641 	 * Get an optional JSONArray associated with a key. It returns null if there
642 	 * is no such key, or if its value is not a JSONArray.
643 	 * 
644 	 * @param key
645 	 *            A key string.
646 	 * @return A JSONArray which is the value.
647 	 */
648 	public JSONArray optJSONArray(String key) {
649 		Object o = opt(key);
650 		return o instanceof JSONArray ? (JSONArray) o : null;
651 	}
652 
653 	/**
654 	 * Get an optional JSONObject associated with a key. It returns null if
655 	 * there is no such key, or if its value is not a JSONObject.
656 	 * 
657 	 * @param key
658 	 *            A key string.
659 	 * @return A JSONObject which is the value.
660 	 */
661 	public JSONObject optJSONObject(String key) {
662 		Object o = opt(key);
663 		return o instanceof JSONObject ? (JSONObject) o : null;
664 	}
665 
666 	/**
667 	 * Get an optional string associated with a key. It returns an empty string
668 	 * if there is no such key. If the value is not a string and is not null,
669 	 * then it is coverted to a string.
670 	 * 
671 	 * @param key
672 	 *            A key string.
673 	 * @return A string which is the value.
674 	 */
675 	public String optString(String key) {
676 		return optString(key, "");
677 	}
678 
679 	/**
680 	 * Get an optional string associated with a key. It returns the defaultValue
681 	 * if there is no such key.
682 	 * 
683 	 * @param key
684 	 *            A key string.
685 	 * @param defaultValue
686 	 *            The default.
687 	 * @return A string which is the value.
688 	 */
689 	public String optString(String key, String defaultValue) {
690 		Object o = opt(key);
691 		return o != null ? o.toString() : defaultValue;
692 	}
693 
694 	/**
695 	 * Put a key/boolean pair in the JSONObject.
696 	 * 
697 	 * @param key
698 	 *            A key string.
699 	 * @param value
700 	 *            A boolean which is the value.
701 	 * @return this.
702 	 */
703 	public JSONObject put(String key, boolean value) {
704 		put(key, Boolean.valueOf(value));
705 		return this;
706 	}
707 
708 	/**
709 	 * Put a key/double pair in the JSONObject.
710 	 * 
711 	 * @param key
712 	 *            A key string.
713 	 * @param value
714 	 *            A double which is the value.
715 	 * @return this.
716 	 */
717 	public JSONObject put(String key, double value) {
718 		put(key, new Double(value));
719 		return this;
720 	}
721 
722 	/**
723 	 * Put a key/int pair in the JSONObject.
724 	 * 
725 	 * @param key
726 	 *            A key string.
727 	 * @param value
728 	 *            An int which is the value.
729 	 * @return this.
730 	 */
731 	public JSONObject put(String key, int value) {
732 		put(key, new Integer(value));
733 		return this;
734 	}
735 
736 	/**
737 	 * Put a key/value pair in the JSONObject. If the value is null, then the
738 	 * key will be removed from the JSONObject if it is present.
739 	 * 
740 	 * @exception NullPointerException
741 	 *                The key must be non-null.
742 	 * @param key
743 	 *            A key string.
744 	 * @param value
745 	 *            An object which is the value. It should be of one of these
746 	 *            types: Boolean, Double, Integer, JSONArray, JSONObject,
747 	 *            String, or the JSONObject.NULL object.
748 	 * @return this.
749 	 */
750 	@SuppressWarnings("unchecked")
751 	public JSONObject put(String key, Object value) throws NullPointerException {
752 		if (key == null) {
753 			throw new NullPointerException("Null key.");
754 		}
755 		if (value != null) {
756 			myHashMap.put(key, value);
757 		} else {
758 			remove(key);
759 		}
760 		return this;
761 	}
762 
763 	/**
764 	 * Put a key/value pair in the JSONObject, but only if the value is
765 	 * non-null.
766 	 * 
767 	 * @exception NullPointerException
768 	 *                The key must be non-null.
769 	 * @param key
770 	 *            A key string.
771 	 * @param value
772 	 *            An object which is the value. It should be of one of these
773 	 *            types: Boolean, Double, Integer, JSONArray, JSONObject,
774 	 *            String, or the JSONObject.NULL object.
775 	 * @return this.
776 	 */
777 	public JSONObject putOpt(String key, Object value)
778 			throws NullPointerException {
779 		if (value != null) {
780 			put(key, value);
781 		}
782 		return this;
783 	}
784 
785 	/**
786 	 * Produce a string in double quotes with backslash sequences in all the
787 	 * right places.
788 	 * 
789 	 * @param string
790 	 *            A String
791 	 * @return A String correctly formatted for insertion in a JSON message.
792 	 */
793 	public static String quote(String string) {
794 		if (string == null || string.length() == 0) {
795 			return "\"\"";
796 		}
797 
798 		char b;
799 		char c = 0;
800 		int i;
801 		int len = string.length();
802 		StringBuffer sb = new StringBuffer(len + 4);
803 		String t;
804 
805 		sb.append('"');
806 		for (i = 0; i < len; i += 1) {
807 			b = c;
808 			c = string.charAt(i);
809 			switch (c) {
810 			case '\\':
811 			case '"':
812 				sb.append('\\');
813 				sb.append(c);
814 				break;
815 			case '/':
816 				if (b == '<') {
817 					sb.append('\\');
818 				}
819 				sb.append(c);
820 				break;
821 			case '\b':
822 				sb.append("\\b");
823 				break;
824 			case '\t':
825 				sb.append("\\t");
826 				break;
827 			case '\n':
828 				sb.append("\\n");
829 				break;
830 			case '\f':
831 				sb.append("\\f");
832 				break;
833 			case '\r':
834 				sb.append("\\r");
835 				break;
836 			default:
837 				if (c < ' ') {
838 					t = "000" + Integer.toHexString(c);
839 					sb.append("\\u" + t.substring(t.length() - 4));
840 				} else {
841 					sb.append(c);
842 				}
843 			}
844 		}
845 		sb.append('"');
846 		return sb.toString();
847 	}
848 
849 	/**
850 	 * Remove a name and its value, if present.
851 	 * 
852 	 * @param key
853 	 *            The name to be removed.
854 	 * @return The value that was associated with the name, or null if there was
855 	 *         no value.
856 	 */
857 	public Object remove(String key) {
858 		return myHashMap.remove(key);
859 	}
860 
861 	/**
862 	 * Produce a JSONArray containing the values of the members of this
863 	 * JSONObject.
864 	 * 
865 	 * @param names
866 	 *            A JSONArray containing a list of key strings. This determines
867 	 *            the sequence of the values in the result.
868 	 * @return A JSONArray of values.
869 	 */
870 	public JSONArray toJSONArray(JSONArray names) {
871 		if (names == null || names.length() == 0) {
872 			return null;
873 		}
874 		JSONArray ja = new JSONArray();
875 		for (int i = 0; i < names.length(); i += 1) {
876 			ja.put(this.opt(names.getString(i)));
877 		}
878 		return ja;
879 	}
880 
881 	/**
882 	 * Make an JSON external form string of this JSONObject. For compactness, no
883 	 * unnecessary whitespace is added.
884 	 * <p>
885 	 * Warning: This method assumes that the data structure is acyclical.
886 	 * 
887 	 * @return a printable, displayable, portable, transmittable representation
888 	 *         of the object, beginning with <code>{</code>&nbsp;<small>(left
889 	 *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
890 	 *         brace)</small>.
891 	 */
892 	public String toString() {
893 		Iterator keys = keys();
894 		StringBuffer sb = new StringBuffer("{");
895 
896 		while (keys.hasNext()) {
897 			if (sb.length() > 1) {
898 				sb.append(',');
899 			}
900 			Object o = keys.next();
901 			sb.append(quote(o.toString()));
902 			sb.append(':');
903 			sb.append(valueToString(myHashMap.get(o)));
904 		}
905 		sb.append('}');
906 		return sb.toString();
907 	}
908 
909 	/**
910 	 * Make a prettyprinted JSON external form string of this JSONObject.
911 	 * <p>
912 	 * Warning: This method assumes that the data structure is acyclical.
913 	 * 
914 	 * @param indentFactor
915 	 *            The number of spaces to add to each level of indentation.
916 	 * @return a printable, displayable, portable, transmittable representation
917 	 *         of the object, beginning with <code>{</code>&nbsp;<small>(left
918 	 *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
919 	 *         brace)</small>.
920 	 */
921 	public String toString(int indentFactor) {
922 		return toString(indentFactor, 0);
923 	}
924 
925 	/**
926 	 * Make a prettyprinted JSON string of this JSONObject.
927 	 * <p>
928 	 * Warning: This method assumes that the data structure is acyclical.
929 	 * 
930 	 * @param indentFactor
931 	 *            The number of spaces to add to each level of indentation.
932 	 * @param indent
933 	 *            The indentation of the top level.
934 	 * @return a printable, displayable, transmittable representation of the
935 	 *         object, beginning with <code>{</code>&nbsp;<small>(left
936 	 *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
937 	 *         brace)</small>.
938 	 */
939 	String toString(int indentFactor, int indent) {
940 		int i;
941 		int n = length();
942 		if (n == 0) {
943 			return "{}";
944 		}
945 		Iterator keys = keys();
946 		StringBuffer sb = new StringBuffer("{");
947 		int newindent = indent + indentFactor;
948 		Object o;
949 		if (n == 1) {
950 			o = keys.next();
951 			sb.append(quote(o.toString()));
952 			sb.append(": ");
953 			sb.append(valueToString(myHashMap.get(o), indentFactor, indent));
954 		} else {
955 			while (keys.hasNext()) {
956 				o = keys.next();
957 				if (sb.length() > 1) {
958 					sb.append(",\n");
959 				} else {
960 					sb.append('\n');
961 				}
962 				for (i = 0; i < newindent; i += 1) {
963 					sb.append(' ');
964 				}
965 				sb.append(quote(o.toString()));
966 				sb.append(": ");
967 				sb.append(valueToString(myHashMap.get(o), indentFactor,
968 						newindent));
969 			}
970 			if (sb.length() > 1) {
971 				sb.append('\n');
972 				for (i = 0; i < indent; i += 1) {
973 					sb.append(' ');
974 				}
975 			}
976 		}
977 		sb.append('}');
978 		return sb.toString();
979 	}
980 
981 	/**
982 	 * Make JSON string of an object value.
983 	 * <p>
984 	 * Warning: This method assumes that the data structure is acyclical.
985 	 * 
986 	 * @param value
987 	 *            The value to be serialized.
988 	 * @return a printable, displayable, transmittable representation of the
989 	 *         object, beginning with <code>{</code>&nbsp;<small>(left
990 	 *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
991 	 *         brace)</small>.
992 	 */
993 	static String valueToString(Object value) throws ArithmeticException {
994 		if (value == null || value.equals(null)) {
995 			return "null";
996 		}
997 		if (value instanceof Number) {
998 			return numberToString((Number) value);
999 		}
1000 		if (value instanceof Boolean || value instanceof JSONObject
1001 				|| value instanceof JSONArray) {
1002 			return value.toString();
1003 		}
1004 		return quote(value.toString());
1005 	}
1006 
1007 	/**
1008 	 * Make a prettyprinted JSON string of an object value.
1009 	 * <p>
1010 	 * Warning: This method assumes that the data structure is acyclical.
1011 	 * 
1012 	 * @param value
1013 	 *            The value to be serialized.
1014 	 * @param indentFactor
1015 	 *            The number of spaces to add to each level of indentation.
1016 	 * @param indent
1017 	 *            The indentation of the top level.
1018 	 * @return a printable, displayable, transmittable representation of the
1019 	 *         object, beginning with <code>{</code>&nbsp;<small>(left
1020 	 *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
1021 	 *         brace)</small>.
1022 	 */
1023 	static String valueToString(Object value, int indentFactor, int indent)
1024 			throws ArithmeticException {
1025 		if (value == null || value.equals(null)) {
1026 			return "null";
1027 		}
1028 		if (value instanceof Number) {
1029 			return numberToString((Number) value);
1030 		}
1031 		if (value instanceof Boolean) {
1032 			return value.toString();
1033 		}
1034 		if (value instanceof JSONObject) {
1035 			return (((JSONObject) value).toString(indentFactor, indent));
1036 		}
1037 		if (value instanceof JSONArray) {
1038 			return (((JSONArray) value).toString(indentFactor, indent));
1039 		}
1040 		return quote(value.toString());
1041 	}
1042 }