001package org.json;
002
003/*
004Copyright (c) 2002 JSON.org
005
006Permission is hereby granted, free of charge, to any person obtaining a copy
007of this software and associated documentation files (the "Software"), to deal
008in the Software without restriction, including without limitation the rights
009to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010copies of the Software, and to permit persons to whom the Software is
011furnished to do so, subject to the following conditions:
012
013The above copyright notice and this permission notice shall be included in all
014copies or substantial portions of the Software.
015
016The Software shall be used for Good, not Evil.
017
018THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
021AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
023OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
024SOFTWARE.
025 */
026
027import java.io.IOException;
028import java.io.Writer;
029import java.lang.reflect.Array;
030import java.util.ArrayList;
031import java.util.Collection;
032import java.util.Iterator;
033import java.util.Map;
034
035/**
036 * A JSONArray is an ordered sequence of values. Its external text form is a
037 * string wrapped in square brackets with commas separating the values. The
038 * internal form is an object having <code>get</code> and <code>opt</code>
039 * methods for accessing the values by index, and <code>put</code> methods for
040 * adding or replacing values. The values can be any of these types:
041 * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
042 * <code>Number</code>, <code>String</code>, or the
043 * <code>JSONObject.NULL object</code>.
044 * <p>
045 * The constructor can convert a JSON text into a Java object. The
046 * <code>toString</code> method converts to JSON text.
047 * <p>
048 * A <code>get</code> method returns a value if one can be found, and throws an
049 * exception if one cannot be found. An <code>opt</code> method returns a
050 * default value instead of throwing an exception, and so is useful for
051 * obtaining optional values.
052 * <p>
053 * The generic <code>get()</code> and <code>opt()</code> methods return an
054 * object which you can cast or query for type. There are also typed
055 * <code>get</code> and <code>opt</code> methods that do type checking and type
056 * coercion for you.
057 * <p>
058 * The texts produced by the <code>toString</code> methods strictly conform to
059 * JSON syntax rules. The constructors are more forgiving in the texts they will
060 * accept:
061 * <ul>
062 * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
063 *     before the closing bracket.</li>
064 * <li>The <code>null</code> value will be inserted when there
065 *     is <code>,</code>&nbsp;<small>(comma)</small> elision.</li>
066 * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
067 *     quote)</small>.</li>
068 * <li>Strings do not need to be quoted at all if they do not begin with a quote
069 *     or single quote, and if they do not contain leading or trailing spaces,
070 *     and if they do not contain any of these characters:
071 *     <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
072 *     and if they are not the reserved words <code>true</code>,
073 *     <code>false</code>, or <code>null</code>.</li>
074 * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
075 *     well as by <code>,</code> <small>(comma)</small>.</li>
076 * <li>Numbers may have the
077 *     <code>0x-</code> <small>(hex)</small> prefix.</li>
078 * </ul>
079
080 * @author JSON.org
081@version $Id$
082@since Ptolemy II 10.0
083 * @version 2009-04-14
084 */
085public class JSONArray {
086
087    /**
088     * The arrayList where the JSONArray's properties are kept.
089     */
090    private ArrayList myArrayList;
091
092    /**
093     * Construct an empty JSONArray.
094     */
095    public JSONArray() {
096        this.myArrayList = new ArrayList();
097    }
098
099    /**
100     * Construct a JSONArray from a JSONTokener.
101     * @param x A JSONTokener
102     * @exception JSONException If there is a syntax error.
103     */
104    public JSONArray(JSONTokener x) throws JSONException {
105        this();
106        char c = x.nextClean();
107        char q;
108        if (c == '[') {
109            q = ']';
110        } else if (c == '(') {
111            q = ')';
112        } else {
113            throw x.syntaxError("A JSONArray text must start with '['");
114        }
115        if (x.nextClean() == ']') {
116            return;
117        }
118        x.back();
119        for (;;) {
120            if (x.nextClean() == ',') {
121                x.back();
122                this.myArrayList.add(null);
123            } else {
124                x.back();
125                this.myArrayList.add(x.nextValue());
126            }
127            c = x.nextClean();
128            switch (c) {
129            case ';':
130            case ',':
131                if (x.nextClean() == ']') {
132                    return;
133                }
134                x.back();
135                break;
136            case ']':
137            case ')':
138                if (q != c) {
139                    throw x.syntaxError(
140                            "Expected a '" + new Character(q) + "'");
141                }
142                return;
143            default:
144                throw x.syntaxError("Expected a ',' or ']'");
145            }
146        }
147    }
148
149    /**
150     * Construct a JSONArray from a source JSON text.
151     * @param source     A string that begins with
152     * <code>[</code>&nbsp;<small>(left bracket)</small>
153     *  and ends with <code>]</code>&nbsp;<small>(right bracket)</small>.
154     *  @exception JSONException If there is a syntax error.
155     */
156    public JSONArray(String source) throws JSONException {
157        this(new JSONTokener(source));
158    }
159
160    /**
161     * Construct a JSONArray from a Collection.
162     * @param collection     A Collection.
163     */
164    public JSONArray(Collection collection) {
165        this.myArrayList = new ArrayList();
166        if (collection != null) {
167            Iterator iter = collection.iterator();
168            while (iter.hasNext()) {
169                Object o = iter.next();
170                this.myArrayList.add(JSONObject.wrap(o));
171            }
172        }
173    }
174
175    /**
176     * Construct a JSONArray from an array
177     * @exception JSONException If not an array.
178     */
179    public JSONArray(Object array) throws JSONException {
180        this();
181        if (array.getClass().isArray()) {
182            int length = Array.getLength(array);
183            for (int i = 0; i < length; i += 1) {
184                this.put(JSONObject.wrap(Array.get(array, i)));
185            }
186        } else {
187            throw new JSONException(
188                    "JSONArray initial value should be a string or collection or array.");
189        }
190    }
191
192    /**
193     * Get the object value associated with an index.
194     * @param index
195     *  The index must be between 0 and length() - 1.
196     * @return An object value.
197     * @exception JSONException If there is no value for the index.
198     */
199    public Object get(int index) throws JSONException {
200        Object o = opt(index);
201        if (o == null) {
202            throw new JSONException("JSONArray[" + index + "] not found.");
203        }
204        return o;
205    }
206
207    /**
208     * Get the boolean value associated with an index.
209     * The string values "true" and "false" are converted to boolean.
210     *
211     * @param index The index must be between 0 and length() - 1.
212     * @return      The truth.
213     * @exception JSONException If there is no value for the index or if the
214     *  value is not convertable to boolean.
215     */
216    public boolean getBoolean(int index) throws JSONException {
217        Object o = get(index);
218        if (o.equals(Boolean.FALSE) || o instanceof String
219                && ((String) o).equalsIgnoreCase("false")) {
220            return false;
221        } else if (o.equals(Boolean.TRUE) || o instanceof String
222                && ((String) o).equalsIgnoreCase("true")) {
223            return true;
224        }
225        throw new JSONException("JSONArray[" + index + "] is not a Boolean.");
226    }
227
228    /**
229     * Get the double value associated with an index.
230     *
231     * @param index The index must be between 0 and length() - 1.
232     * @return      The value.
233     * @exception   JSONException If the key is not found or if the value cannot
234     *  be converted to a number.
235     */
236    public double getDouble(int index) throws JSONException {
237        Object o = get(index);
238        try {
239            return o instanceof Number ? ((Number) o).doubleValue()
240                    : Double.valueOf((String) o).doubleValue();
241        } catch (Exception e) {
242            throw new JSONException(
243                    "JSONArray[" + index + "] is not a number.");
244        }
245    }
246
247    /**
248     * Get the int value associated with an index.
249     *
250     * @param index The index must be between 0 and length() - 1.
251     * @return      The value.
252     * @exception   JSONException If the key is not found or if the value cannot
253     *  be converted to a number.
254     *  if the value cannot be converted to a number.
255     */
256    public int getInt(int index) throws JSONException {
257        Object o = get(index);
258        return o instanceof Number ? ((Number) o).intValue()
259                : (int) getDouble(index);
260    }
261
262    /**
263     * Get the JSONArray associated with an index.
264     * @param index The index must be between 0 and length() - 1.
265     * @return      A JSONArray value.
266     * @exception JSONException If there is no value for the index. or if the
267     * value is not a JSONArray
268     */
269    public JSONArray getJSONArray(int index) throws JSONException {
270        Object o = get(index);
271        if (o instanceof JSONArray) {
272            return (JSONArray) o;
273        }
274        throw new JSONException("JSONArray[" + index + "] is not a JSONArray.");
275    }
276
277    /**
278     * Get the JSONObject associated with an index.
279     * @param index subscript
280     * @return      A JSONObject value.
281     * @exception JSONException If there is no value for the index or if the
282     * value is not a JSONObject
283     */
284    public JSONObject getJSONObject(int index) throws JSONException {
285        Object o = get(index);
286        if (o instanceof JSONObject) {
287            return (JSONObject) o;
288        }
289        throw new JSONException(
290                "JSONArray[" + index + "] is not a JSONObject.");
291    }
292
293    /**
294     * Get the long value associated with an index.
295     *
296     * @param index The index must be between 0 and length() - 1.
297     * @return      The value.
298     * @exception   JSONException If the key is not found or if the value cannot
299     *  be converted to a number.
300     */
301    public long getLong(int index) throws JSONException {
302        Object o = get(index);
303        return o instanceof Number ? ((Number) o).longValue()
304                : (long) getDouble(index);
305    }
306
307    /**
308     * Get the string associated with an index.
309     * @param index The index must be between 0 and length() - 1.
310     * @return      A string value.
311     * @exception JSONException If there is no value for the index.
312     */
313    public String getString(int index) throws JSONException {
314        return get(index).toString();
315    }
316
317    /**
318     * Determine if the value is null.
319     * @param index The index must be between 0 and length() - 1.
320     * @return true if the value at the index is null, or if there is no value.
321     */
322    public boolean isNull(int index) {
323        return JSONObject.NULL.equals(opt(index));
324    }
325
326    /**
327     * Make a string from the contents of this JSONArray. The
328     * <code>separator</code> string is inserted between each element.
329     * Warning: This method assumes that the data structure is acyclical.
330     * @param separator A string that will be inserted between the elements.
331     * @return a string.
332     * @exception JSONException If the array contains an invalid number.
333     */
334    public String join(String separator) throws JSONException {
335        int len = length();
336        StringBuffer sb = new StringBuffer();
337
338        for (int i = 0; i < len; i += 1) {
339            if (i > 0) {
340                sb.append(separator);
341            }
342            sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
343        }
344        return sb.toString();
345    }
346
347    /**
348     * Get the number of elements in the JSONArray, included nulls.
349     *
350     * @return The length (or size).
351     */
352    public int length() {
353        return this.myArrayList.size();
354    }
355
356    /**
357     * Get the optional object value associated with an index.
358     * @param index The index must be between 0 and length() - 1.
359     * @return      An object value, or null if there is no
360     *              object at that index.
361     */
362    public Object opt(int index) {
363        return index < 0 || index >= length() ? null
364                : this.myArrayList.get(index);
365    }
366
367    /**
368     * Get the optional boolean value associated with an index.
369     * It returns false if there is no value at that index,
370     * or if the value is not Boolean.TRUE or the String "true".
371     *
372     * @param index The index must be between 0 and length() - 1.
373     * @return      The truth.
374     */
375    public boolean optBoolean(int index) {
376        return optBoolean(index, false);
377    }
378
379    /**
380     * Get the optional boolean value associated with an index.
381     * It returns the defaultValue if there is no value at that index or if
382     * it is not a Boolean or the String "true" or "false" (case insensitive).
383     *
384     * @param index The index must be between 0 and length() - 1.
385     * @param defaultValue     A boolean default.
386     * @return      The truth.
387     */
388    public boolean optBoolean(int index, boolean defaultValue) {
389        try {
390            return getBoolean(index);
391        } catch (Exception e) {
392            return defaultValue;
393        }
394    }
395
396    /**
397     * Get the optional double value associated with an index.
398     * NaN is returned if there is no value for the index,
399     * or if the value is not a number and cannot be converted to a number.
400     *
401     * @param index The index must be between 0 and length() - 1.
402     * @return      The value.
403     */
404    public double optDouble(int index) {
405        return optDouble(index, Double.NaN);
406    }
407
408    /**
409     * Get the optional double value associated with an index.
410     * The defaultValue is returned if there is no value for the index,
411     * or if the value is not a number and cannot be converted to a number.
412     *
413     * @param index subscript
414     * @param defaultValue     The default value.
415     * @return      The value.
416     */
417    public double optDouble(int index, double defaultValue) {
418        try {
419            return getDouble(index);
420        } catch (Exception e) {
421            return defaultValue;
422        }
423    }
424
425    /**
426     * Get the optional int value associated with an index.
427     * Zero is returned if there is no value for the index,
428     * or if the value is not a number and cannot be converted to a number.
429     *
430     * @param index The index must be between 0 and length() - 1.
431     * @return      The value.
432     */
433    public int optInt(int index) {
434        return optInt(index, 0);
435    }
436
437    /**
438     * Get the optional int value associated with an index.
439     * The defaultValue is returned if there is no value for the index,
440     * or if the value is not a number and cannot be converted to a number.
441     * @param index The index must be between 0 and length() - 1.
442     * @param defaultValue     The default value.
443     * @return      The value.
444     */
445    public int optInt(int index, int defaultValue) {
446        try {
447            return getInt(index);
448        } catch (Exception e) {
449            return defaultValue;
450        }
451    }
452
453    /**
454     * Get the optional JSONArray associated with an index.
455     * @param index subscript
456     * @return      A JSONArray value, or null if the index has no value,
457     * or if the value is not a JSONArray.
458     */
459    public JSONArray optJSONArray(int index) {
460        Object o = opt(index);
461        return o instanceof JSONArray ? (JSONArray) o : null;
462    }
463
464    /**
465     * Get the optional JSONObject associated with an index.
466     * Null is returned if the key is not found, or null if the index has
467     * no value, or if the value is not a JSONObject.
468     *
469     * @param index The index must be between 0 and length() - 1.
470     * @return      A JSONObject value.
471     */
472    public JSONObject optJSONObject(int index) {
473        Object o = opt(index);
474        return o instanceof JSONObject ? (JSONObject) o : null;
475    }
476
477    /**
478     * Get the optional long value associated with an index.
479     * Zero is returned if there is no value for the index,
480     * or if the value is not a number and cannot be converted to a number.
481     *
482     * @param index The index must be between 0 and length() - 1.
483     * @return      The value.
484     */
485    public long optLong(int index) {
486        return optLong(index, 0);
487    }
488
489    /**
490     * Get the optional long value associated with an index.
491     * The defaultValue is returned if there is no value for the index,
492     * or if the value is not a number and cannot be converted to a number.
493     * @param index The index must be between 0 and length() - 1.
494     * @param defaultValue     The default value.
495     * @return      The value.
496     */
497    public long optLong(int index, long defaultValue) {
498        try {
499            return getLong(index);
500        } catch (Exception e) {
501            return defaultValue;
502        }
503    }
504
505    /**
506     * Get the optional string value associated with an index. It returns an
507     * empty string if there is no value at that index. If the value
508     * is not a string and is not null, then it is converted to a string.
509     *
510     * @param index The index must be between 0 and length() - 1.
511     * @return      A String value.
512     */
513    public String optString(int index) {
514        return optString(index, "");
515    }
516
517    /**
518     * Get the optional string associated with an index.
519     * The defaultValue is returned if the key is not found.
520     *
521     * @param index The index must be between 0 and length() - 1.
522     * @param defaultValue     The default value.
523     * @return      A String value.
524     */
525    public String optString(int index, String defaultValue) {
526        Object o = opt(index);
527        return o != null ? o.toString() : defaultValue;
528    }
529
530    /**
531     * Append a boolean value. This increases the array's length by one.
532     *
533     * @param value A boolean value.
534     * @return this.
535     */
536    public JSONArray put(boolean value) {
537        put(value ? Boolean.TRUE : Boolean.FALSE);
538        return this;
539    }
540
541    /**
542     * Put a value in the JSONArray, where the value will be a
543     * JSONArray which is produced from a Collection.
544     * @param value A Collection value.
545     * @return      this.
546     */
547    public JSONArray put(Collection value) {
548        put(new JSONArray(value));
549        return this;
550    }
551
552    /**
553     * Append a double value. This increases the array's length by one.
554     *
555     * @param value A double value.
556     * @exception JSONException if the value is not finite.
557     * @return this.
558     */
559    public JSONArray put(double value) throws JSONException {
560        Double d = new Double(value);
561        JSONObject.testValidity(d);
562        put(d);
563        return this;
564    }
565
566    /**
567     * Append an int value. This increases the array's length by one.
568     *
569     * @param value An int value.
570     * @return this.
571     */
572    public JSONArray put(int value) {
573        put(new Integer(value));
574        return this;
575    }
576
577    /**
578     * Append an long value. This increases the array's length by one.
579     *
580     * @param value A long value.
581     * @return this.
582     */
583    public JSONArray put(long value) {
584        put(new Long(value));
585        return this;
586    }
587
588    /**
589     * Put a value in the JSONArray, where the value will be a
590     * JSONObject which is produced from a Map.
591     * @param value A Map value.
592     * @return      this.
593     */
594    public JSONArray put(Map value) {
595        put(new JSONObject(value));
596        return this;
597    }
598
599    /**
600     * Append an object value. This increases the array's length by one.
601     * @param value An object value.  The value should be a
602     *  Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
603     *  JSONObject.NULL object.
604     * @return this.
605     */
606    public JSONArray put(Object value) {
607        this.myArrayList.add(value);
608        return this;
609    }
610
611    /**
612     * Put or replace a boolean value in the JSONArray. If the index is greater
613     * than the length of the JSONArray, then null elements will be added as
614     * necessary to pad it out.
615     * @param index The subscript.
616     * @param value A boolean value.
617     * @return this.
618     * @exception JSONException If the index is negative.
619     */
620    public JSONArray put(int index, boolean value) throws JSONException {
621        put(index, value ? Boolean.TRUE : Boolean.FALSE);
622        return this;
623    }
624
625    /**
626     * Put a value in the JSONArray, where the value will be a
627     * JSONArray which is produced from a Collection.
628     * @param index The subscript.
629     * @param value A Collection value.
630     * @return      this.
631     * @exception JSONException If the index is negative or if the value is
632     * not finite.
633     */
634    public JSONArray put(int index, Collection value) throws JSONException {
635        put(index, new JSONArray(value));
636        return this;
637    }
638
639    /**
640     * Put or replace a double value. If the index is greater than the length of
641     *  the JSONArray, then null elements will be added as necessary to pad
642     *  it out.
643     * @param index The subscript.
644     * @param value A double value.
645     * @return this.
646     * @exception JSONException If the index is negative or if the value is
647     * not finite.
648     */
649    public JSONArray put(int index, double value) throws JSONException {
650        put(index, new Double(value));
651        return this;
652    }
653
654    /**
655     * Put or replace an int value. If the index is greater than the length of
656     *  the JSONArray, then null elements will be added as necessary to pad
657     *  it out.
658     * @param index The subscript.
659     * @param value An int value.
660     * @return this.
661     * @exception JSONException If the index is negative.
662     */
663    public JSONArray put(int index, int value) throws JSONException {
664        put(index, new Integer(value));
665        return this;
666    }
667
668    /**
669     * Put or replace a long value. If the index is greater than the length of
670     *  the JSONArray, then null elements will be added as necessary to pad
671     *  it out.
672     * @param index The subscript.
673     * @param value A long value.
674     * @return this.
675     * @exception JSONException If the index is negative.
676     */
677    public JSONArray put(int index, long value) throws JSONException {
678        put(index, new Long(value));
679        return this;
680    }
681
682    /**
683     * Put a value in the JSONArray, where the value will be a
684     * JSONObject which is produced from a Map.
685     * @param index The subscript.
686     * @param value The Map value.
687     * @return      this.
688     * @exception JSONException If the index is negative or if the the value is
689     *  an invalid number.
690     */
691    public JSONArray put(int index, Map value) throws JSONException {
692        put(index, new JSONObject(value));
693        return this;
694    }
695
696    /**
697     * Put or replace an object value in the JSONArray. If the index is greater
698     *  than the length of the JSONArray, then null elements will be added as
699     *  necessary to pad it out.
700     * @param index The subscript.
701     * @param value The value to put into the array. The value should be a
702     *  Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
703     *  JSONObject.NULL object.
704     * @return this.
705     * @exception JSONException If the index is negative or if the the value is
706     *  an invalid number.
707     */
708    public JSONArray put(int index, Object value) throws JSONException {
709        JSONObject.testValidity(value);
710        if (index < 0) {
711            throw new JSONException("JSONArray[" + index + "] not found.");
712        }
713        if (index < length()) {
714            this.myArrayList.set(index, value);
715        } else {
716            while (index != length()) {
717                put(JSONObject.NULL);
718            }
719            put(value);
720        }
721        return this;
722    }
723
724    /**
725     * Remove an index and close the hole.
726     * @param index The index of the element to be removed.
727     * @return The value that was associated with the index,
728     * or null if there was no value.
729     */
730    public Object remove(int index) {
731        Object o = opt(index);
732        this.myArrayList.remove(index);
733        return o;
734    }
735
736    /**
737     * Produce a JSONObject by combining a JSONArray of names with the values
738     * of this JSONArray.
739     * @param names A JSONArray containing a list of key strings. These will be
740     * paired with the values.
741     * @return A JSONObject, or null if there are no names or if this JSONArray
742     * has no values.
743     * @exception JSONException If any of the names are null.
744     */
745    public JSONObject toJSONObject(JSONArray names) throws JSONException {
746        if (names == null || names.length() == 0 || length() == 0) {
747            return null;
748        }
749        JSONObject jo = new JSONObject();
750        for (int i = 0; i < names.length(); i += 1) {
751            jo.put(names.getString(i), this.opt(i));
752        }
753        return jo;
754    }
755
756    /**
757     * Make a JSON text of this JSONArray. For compactness, no
758     * unnecessary whitespace is added. If it is not possible to produce a
759     * syntactically correct JSON text then null will be returned instead. This
760     * could occur if the array contains an invalid number.
761     * <p>
762     * Warning: This method assumes that the data structure is acyclical.
763     *
764     * @return a printable, displayable, transmittable
765     *  representation of the array.
766     */
767    @Override
768    public String toString() {
769        try {
770            return '[' + join(",") + ']';
771        } catch (Exception e) {
772            return null;
773        }
774    }
775
776    /**
777     * Make a prettyprinted JSON text of this JSONArray.
778     * Warning: This method assumes that the data structure is acyclical.
779     * @param indentFactor The number of spaces to add to each level of
780     *  indentation.
781     * @return a printable, displayable, transmittable
782     *  representation of the object, beginning
783     *  with <code>[</code>&nbsp;<small>(left bracket)</small> and ending
784     *  with <code>]</code>&nbsp;<small>(right bracket)</small>.
785     * @exception JSONException
786     */
787    public String toString(int indentFactor) throws JSONException {
788        return toString(indentFactor, 0);
789    }
790
791    /**
792     * Make a prettyprinted JSON text of this JSONArray.
793     * Warning: This method assumes that the data structure is acyclical.
794     * @param indentFactor The number of spaces to add to each level of
795     *  indentation.
796     * @param indent The indention of the top level.
797     * @return a printable, displayable, transmittable
798     *  representation of the array.
799     * @exception JSONException
800     */
801    String toString(int indentFactor, int indent) throws JSONException {
802        int len = length();
803        if (len == 0) {
804            return "[]";
805        }
806        int i;
807        StringBuffer sb = new StringBuffer("[");
808        if (len == 1) {
809            sb.append(JSONObject.valueToString(this.myArrayList.get(0),
810                    indentFactor, indent));
811        } else {
812            int newindent = indent + indentFactor;
813            sb.append('\n');
814            for (i = 0; i < len; i += 1) {
815                if (i > 0) {
816                    sb.append(",\n");
817                }
818                for (int j = 0; j < newindent; j += 1) {
819                    sb.append(' ');
820                }
821                sb.append(JSONObject.valueToString(this.myArrayList.get(i),
822                        indentFactor, newindent));
823            }
824            sb.append('\n');
825            for (i = 0; i < indent; i += 1) {
826                sb.append(' ');
827            }
828        }
829        sb.append(']');
830        return sb.toString();
831    }
832
833    /**
834     * Write the contents of the JSONArray as JSON text to a writer.
835     * For compactness, no whitespace is added.
836     * <p>
837     * Warning: This method assumes that the data structure is acyclical.
838     *
839     * @return The writer.
840     * @exception JSONException
841     */
842    public Writer write(Writer writer) throws JSONException {
843        try {
844            boolean b = false;
845            int len = length();
846
847            writer.write('[');
848
849            for (int i = 0; i < len; i += 1) {
850                if (b) {
851                    writer.write(',');
852                }
853                Object v = this.myArrayList.get(i);
854                if (v instanceof JSONObject) {
855                    ((JSONObject) v).write(writer);
856                } else if (v instanceof JSONArray) {
857                    ((JSONArray) v).write(writer);
858                } else {
859                    writer.write(JSONObject.valueToString(v));
860                }
861                b = true;
862            }
863            writer.write(']');
864            return writer;
865        } catch (IOException e) {
866            throw new JSONException(e);
867        }
868    }
869}