001    /*
002     * Apache License
003     * Version 2.0, January 2004
004     * http://www.apache.org/licenses/
005     *
006     * Copyright 2008 by chenillekit.org
007     *
008     * Licensed under the Apache License, Version 2.0 (the "License");
009     * you may not use this file except in compliance with the License.
010     * You may obtain a copy of the License at
011     *
012     * http://www.apache.org/licenses/LICENSE-2.0
013     *
014     */
015    
016    package org.chenillekit.google.utils;
017    
018    import java.io.IOException;
019    import java.io.Writer;
020    import java.lang.reflect.Array;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.Map;
024    
025    /**
026     * A JSONArray is an ordered sequence of values. Its external text form is a
027     * string wrapped in square brackets with commas separating the values. The
028     * internal form is an object having <code>get</code> and <code>opt</code>
029     * methods for accessing the values by index, and <code>put</code> methods for
030     * adding or replacing values. The values can be any of these types:
031     * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
032     * <code>Number</code>, <code>String</code>, or the
033     * <code>JSONObject.NULL object</code>.
034     * <p/>
035     * The constructor can convert a JSON text into a Java object. The
036     * <code>toString</code> method converts to JSON text.
037     * <p/>
038     * A <code>get</code> method returns a value if one can be found, and throws an
039     * exception if one cannot be found. An <code>opt</code> method returns a
040     * default value instead of throwing an exception, and so is useful for
041     * obtaining optional values.
042     * <p/>
043     * The generic <code>get()</code> and <code>opt()</code> methods return an
044     * object which you can cast or query for type. There are also typed
045     * <code>get</code> and <code>opt</code> methods that do type checking and type
046     * coersion for you.
047     * <p/>
048     * The texts produced by the <code>toString</code> methods strictly conform to
049     * JSON syntax rules. The constructors are more forgiving in the texts they will
050     * accept:
051     * <ul>
052     * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
053     * before the closing bracket.</li>
054     * <li>The <code>null</code> value will be inserted when there
055     * is <code>,</code>&nbsp;<small>(comma)</small> elision.</li>
056     * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
057     * quote)</small>.</li>
058     * <li>Strings do not need to be quoted at all if they do not begin with a quote
059     * or single quote, and if they do not contain leading or trailing spaces,
060     * and if they do not contain any of these characters:
061     * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
062     * and if they are not the reserved words <code>true</code>,
063     * <code>false</code>, or <code>null</code>.</li>
064     * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
065     * well as by <code>,</code> <small>(comma)</small>.</li>
066     * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
067     * <code>0x-</code> <small>(hex)</small> prefix.</li>
068     * <li>Comments written in the slashshlash, slashstar, and hash conventions
069     * will be ignored.</li>
070     * </ul>
071     *
072     * @author JSON.org
073     * @version 3
074     */
075    public class JSONArray
076    {
077    
078    
079        /**
080         * The arrayList where the JSONArray's properties are kept.
081         */
082        private ArrayList myArrayList;
083    
084    
085        /**
086         * Construct an empty JSONArray.
087         */
088        public JSONArray()
089        {
090            this.myArrayList = new ArrayList();
091        }
092    
093        /**
094         * Construct a JSONArray from a JSONTokener.
095         *
096         * @param x A JSONTokener
097         *
098         * @throws JSONException If there is a syntax error.
099         */
100        public JSONArray(JSONTokener x) throws JSONException
101        {
102            this();
103            char c = x.nextClean();
104            char q;
105            if (c == '[')
106            {
107                q = ']';
108            }
109            else if (c == '(')
110            {
111                q = ')';
112            }
113            else
114            {
115                throw x.syntaxError("A JSONArray text must start with '['");
116            }
117            if (x.nextClean() == ']')
118            {
119                return;
120            }
121            x.back();
122            for (; ;)
123            {
124                if (x.nextClean() == ',')
125                {
126                    x.back();
127                    this.myArrayList.add(null);
128                }
129                else
130                {
131                    x.back();
132                    this.myArrayList.add(x.nextValue());
133                }
134                c = x.nextClean();
135                switch (c)
136                {
137                    case ';':
138                    case ',':
139                        if (x.nextClean() == ']')
140                        {
141                            return;
142                        }
143                        x.back();
144                        break;
145                    case ']':
146                    case ')':
147                        if (q != c)
148                        {
149                            throw x.syntaxError("Expected a '" + q + "'");
150                        }
151                        return;
152                    default:
153                        throw x.syntaxError("Expected a ',' or ']'");
154                }
155            }
156        }
157    
158    
159        /**
160         * Construct a JSONArray from a source JSON text.
161         *
162         * @param source A string that begins with
163         *               <code>[</code>&nbsp;<small>(left bracket)</small>
164         *               and ends with <code>]</code>&nbsp;<small>(right bracket)</small>.
165         *
166         * @throws JSONException If there is a syntax error.
167         */
168        public JSONArray(String source) throws JSONException
169        {
170            this(new JSONTokener(source));
171        }
172    
173    
174        /**
175         * Construct a JSONArray from a Collection.
176         *
177         * @param collection A Collection.
178         */
179        public JSONArray(Collection collection)
180        {
181            this.myArrayList = (collection == null) ?
182                    new ArrayList() :
183                    new ArrayList(collection);
184        }
185    
186        /**
187         * Construct a JSONArray from a collection of beans.
188         * The collection should have Java Beans.
189         *
190         * @throws JSONException If not an array.
191         */
192    
193        public JSONArray(Collection collection, boolean includeSuperClass)
194        {
195            this.myArrayList = new ArrayList();
196            if (collection != null)
197            {
198                for (Object aCollection : collection)
199                    this.myArrayList.add(new JSONObject(aCollection, includeSuperClass));
200            }
201        }
202    
203    
204        /**
205         * Construct a JSONArray from an array
206         *
207         * @throws JSONException If not an array.
208         */
209        public JSONArray(Object array) throws JSONException
210        {
211            this();
212            if (array.getClass().isArray())
213            {
214                int length = Array.getLength(array);
215                for (int i = 0; i < length; i += 1)
216                {
217                    this.put(Array.get(array, i));
218                }
219            }
220            else
221            {
222                throw new JSONException("JSONArray initial value should be a string or collection or array.");
223            }
224        }
225    
226        /**
227         * Construct a JSONArray from an array with a bean.
228         * The array should have Java Beans.
229         *
230         * @throws JSONException If not an array.
231         */
232        public JSONArray(Object array, boolean includeSuperClass) throws JSONException
233        {
234            this();
235            if (array.getClass().isArray())
236            {
237                int length = Array.getLength(array);
238                for (int i = 0; i < length; i += 1)
239                {
240                    this.put(new JSONObject(Array.get(array, i), includeSuperClass));
241                }
242            }
243            else
244            {
245                throw new JSONException("JSONArray initial value should be a string or collection or array.");
246            }
247        }
248    
249    
250        /**
251         * Get the object value associated with an index.
252         *
253         * @param index The index must be between 0 and length() - 1.
254         *
255         * @return An object value.
256         *
257         * @throws JSONException If there is no value for the index.
258         */
259        public Object get(int index) throws JSONException
260        {
261            Object o = opt(index);
262            if (o == null)
263            {
264                throw new JSONException("JSONArray[" + index + "] not found.");
265            }
266            return o;
267        }
268    
269    
270        /**
271         * Get the boolean value associated with an index.
272         * The string values "true" and "false" are converted to boolean.
273         *
274         * @param index The index must be between 0 and length() - 1.
275         *
276         * @return The truth.
277         *
278         * @throws JSONException If there is no value for the index or if the
279         *                       value is not convertable to boolean.
280         */
281        public boolean getBoolean(int index) throws JSONException
282        {
283            Object o = get(index);
284            if (o.equals(Boolean.FALSE) ||
285                    (o instanceof String &&
286                            ((String) o).equalsIgnoreCase("false")))
287            {
288                return false;
289            }
290            else if (o.equals(Boolean.TRUE) ||
291                    (o instanceof String &&
292                            ((String) o).equalsIgnoreCase("true")))
293            {
294                return true;
295            }
296            throw new JSONException("JSONArray[" + index + "] is not a Boolean.");
297        }
298    
299    
300        /**
301         * Get the double value associated with an index.
302         *
303         * @param index The index must be between 0 and length() - 1.
304         *
305         * @return The value.
306         *
307         * @throws JSONException If the key is not found or if the value cannot
308         *                       be converted to a number.
309         */
310        public double getDouble(int index) throws JSONException
311        {
312            Object o = get(index);
313            try
314            {
315                return o instanceof Number ?
316                        ((Number) o).doubleValue() : Double.valueOf((String) o);
317            }
318            catch (Exception e)
319            {
320                throw new JSONException("JSONArray[" + index + "] is not a number.");
321            }
322        }
323    
324    
325        /**
326         * Get the int value associated with an index.
327         *
328         * @param index The index must be between 0 and length() - 1.
329         *
330         * @return The value.
331         *
332         * @throws JSONException If the key is not found or if the value cannot
333         *                       be converted to a number.
334         *                       if the value cannot be converted to a number.
335         */
336        public int getInt(int index) throws JSONException
337        {
338            Object o = get(index);
339            return o instanceof Number ?
340                    ((Number) o).intValue() : (int) getDouble(index);
341        }
342    
343    
344        /**
345         * Get the JSONArray associated with an index.
346         *
347         * @param index The index must be between 0 and length() - 1.
348         *
349         * @return A JSONArray value.
350         *
351         * @throws JSONException If there is no value for the index. or if the
352         *                       value is not a JSONArray
353         */
354        public JSONArray getJSONArray(int index) throws JSONException
355        {
356            Object o = get(index);
357            if (o instanceof JSONArray)
358            {
359                return (JSONArray) o;
360            }
361            throw new JSONException("JSONArray[" + index +
362                    "] is not a JSONArray.");
363        }
364    
365    
366        /**
367         * Get the JSONObject associated with an index.
368         *
369         * @param index subscript
370         *
371         * @return A JSONObject value.
372         *
373         * @throws JSONException If there is no value for the index or if the
374         *                       value is not a JSONObject
375         */
376        public JSONObject getJSONObject(int index) throws JSONException
377        {
378            Object o = get(index);
379            if (o instanceof JSONObject)
380            {
381                return (JSONObject) o;
382            }
383            throw new JSONException("JSONArray[" + index +
384                    "] is not a JSONObject.");
385        }
386    
387    
388        /**
389         * Get the long value associated with an index.
390         *
391         * @param index The index must be between 0 and length() - 1.
392         *
393         * @return The value.
394         *
395         * @throws JSONException If the key is not found or if the value cannot
396         *                       be converted to a number.
397         */
398        public long getLong(int index) throws JSONException
399        {
400            Object o = get(index);
401            return o instanceof Number ?
402                    ((Number) o).longValue() : (long) getDouble(index);
403        }
404    
405    
406        /**
407         * Get the string associated with an index.
408         *
409         * @param index The index must be between 0 and length() - 1.
410         *
411         * @return A string value.
412         *
413         * @throws JSONException If there is no value for the index.
414         */
415        public String getString(int index) throws JSONException
416        {
417            return get(index).toString();
418        }
419    
420    
421        /**
422         * Determine if the value is null.
423         *
424         * @param index The index must be between 0 and length() - 1.
425         *
426         * @return true if the value at the index is null, or if there is no value.
427         */
428        public boolean isNull(int index)
429        {
430            return JSONObject.NULL.equals(opt(index));
431        }
432    
433    
434        /**
435         * Make a string from the contents of this JSONArray. The
436         * <code>separator</code> string is inserted between each element.
437         * Warning: This method assumes that the data structure is acyclical.
438         *
439         * @param separator A string that will be inserted between the elements.
440         *
441         * @return a string.
442         *
443         * @throws JSONException If the array contains an invalid number.
444         */
445        public String join(String separator) throws JSONException
446        {
447            int len = length();
448            StringBuffer sb = new StringBuffer();
449    
450            for (int i = 0; i < len; i += 1)
451            {
452                if (i > 0)
453                {
454                    sb.append(separator);
455                }
456                sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
457            }
458            return sb.toString();
459        }
460    
461    
462        /**
463         * Get the number of elements in the JSONArray, included nulls.
464         *
465         * @return The length (or size).
466         */
467        public int length()
468        {
469            return this.myArrayList.size();
470        }
471    
472    
473        /**
474         * Get the optional object value associated with an index.
475         *
476         * @param index The index must be between 0 and length() - 1.
477         *
478         * @return An object value, or null if there is no
479         *         object at that index.
480         */
481        public Object opt(int index)
482        {
483            return (index < 0 || index >= length()) ?
484                    null : this.myArrayList.get(index);
485        }
486    
487    
488        /**
489         * Get the optional boolean value associated with an index.
490         * It returns false if there is no value at that index,
491         * or if the value is not Boolean.TRUE or the String "true".
492         *
493         * @param index The index must be between 0 and length() - 1.
494         *
495         * @return The truth.
496         */
497        public boolean optBoolean(int index)
498        {
499            return optBoolean(index, false);
500        }
501    
502    
503        /**
504         * Get the optional boolean value associated with an index.
505         * It returns the defaultValue if there is no value at that index or if
506         * it is not a Boolean or the String "true" or "false" (case insensitive).
507         *
508         * @param index        The index must be between 0 and length() - 1.
509         * @param defaultValue A boolean default.
510         *
511         * @return The truth.
512         */
513        public boolean optBoolean(int index, boolean defaultValue)
514        {
515            try
516            {
517                return getBoolean(index);
518            }
519            catch (Exception e)
520            {
521                return defaultValue;
522            }
523        }
524    
525    
526        /**
527         * Get the optional double value associated with an index.
528         * NaN is returned if there is no value for the index,
529         * or if the value is not a number and cannot be converted to a number.
530         *
531         * @param index The index must be between 0 and length() - 1.
532         *
533         * @return The value.
534         */
535        public double optDouble(int index)
536        {
537            return optDouble(index, Double.NaN);
538        }
539    
540    
541        /**
542         * Get the optional double value associated with an index.
543         * The defaultValue is returned if there is no value for the index,
544         * or if the value is not a number and cannot be converted to a number.
545         *
546         * @param index        subscript
547         * @param defaultValue The default value.
548         *
549         * @return The value.
550         */
551        public double optDouble(int index, double defaultValue)
552        {
553            try
554            {
555                return getDouble(index);
556            }
557            catch (Exception e)
558            {
559                return defaultValue;
560            }
561        }
562    
563    
564        /**
565         * Get the optional int value associated with an index.
566         * Zero is returned if there is no value for the index,
567         * or if the value is not a number and cannot be converted to a number.
568         *
569         * @param index The index must be between 0 and length() - 1.
570         *
571         * @return The value.
572         */
573        public int optInt(int index)
574        {
575            return optInt(index, 0);
576        }
577    
578    
579        /**
580         * Get the optional int value associated with an index.
581         * The defaultValue is returned if there is no value for the index,
582         * or if the value is not a number and cannot be converted to a number.
583         *
584         * @param index        The index must be between 0 and length() - 1.
585         * @param defaultValue The default value.
586         *
587         * @return The value.
588         */
589        public int optInt(int index, int defaultValue)
590        {
591            try
592            {
593                return getInt(index);
594            }
595            catch (Exception e)
596            {
597                return defaultValue;
598            }
599        }
600    
601    
602        /**
603         * Get the optional JSONArray associated with an index.
604         *
605         * @param index subscript
606         *
607         * @return A JSONArray value, or null if the index has no value,
608         *         or if the value is not a JSONArray.
609         */
610        public JSONArray optJSONArray(int index)
611        {
612            Object o = opt(index);
613            return o instanceof JSONArray ? (JSONArray) o : null;
614        }
615    
616    
617        /**
618         * Get the optional JSONObject associated with an index.
619         * Null is returned if the key is not found, or null if the index has
620         * no value, or if the value is not a JSONObject.
621         *
622         * @param index The index must be between 0 and length() - 1.
623         *
624         * @return A JSONObject value.
625         */
626        public JSONObject optJSONObject(int index)
627        {
628            Object o = opt(index);
629            return o instanceof JSONObject ? (JSONObject) o : null;
630        }
631    
632    
633        /**
634         * Get the optional long value associated with an index.
635         * Zero is returned if there is no value for the index,
636         * or if the value is not a number and cannot be converted to a number.
637         *
638         * @param index The index must be between 0 and length() - 1.
639         *
640         * @return The value.
641         */
642        public long optLong(int index)
643        {
644            return optLong(index, 0);
645        }
646    
647    
648        /**
649         * Get the optional long value associated with an index.
650         * The defaultValue is returned if there is no value for the index,
651         * or if the value is not a number and cannot be converted to a number.
652         *
653         * @param index        The index must be between 0 and length() - 1.
654         * @param defaultValue The default value.
655         *
656         * @return The value.
657         */
658        public long optLong(int index, long defaultValue)
659        {
660            try
661            {
662                return getLong(index);
663            }
664            catch (Exception e)
665            {
666                return defaultValue;
667            }
668        }
669    
670    
671        /**
672         * Get the optional string value associated with an index. It returns an
673         * empty string if there is no value at that index. If the value
674         * is not a string and is not null, then it is coverted to a string.
675         *
676         * @param index The index must be between 0 and length() - 1.
677         *
678         * @return A String value.
679         */
680        public String optString(int index)
681        {
682            return optString(index, "");
683        }
684    
685    
686        /**
687         * Get the optional string associated with an index.
688         * The defaultValue is returned if the key is not found.
689         *
690         * @param index        The index must be between 0 and length() - 1.
691         * @param defaultValue The default value.
692         *
693         * @return A String value.
694         */
695        public String optString(int index, String defaultValue)
696        {
697            Object o = opt(index);
698            return o != null ? o.toString() : defaultValue;
699        }
700    
701    
702        /**
703         * Append a boolean value. This increases the array's length by one.
704         *
705         * @param value A boolean value.
706         *
707         * @return this.
708         */
709        public JSONArray put(boolean value)
710        {
711            put(value ? Boolean.TRUE : Boolean.FALSE);
712            return this;
713        }
714    
715    
716        /**
717         * Put a value in the JSONArray, where the value will be a
718         * JSONArray which is produced from a Collection.
719         *
720         * @param value A Collection value.
721         *
722         * @return this.
723         */
724        public JSONArray put(Collection value)
725        {
726            put(new JSONArray(value));
727            return this;
728        }
729    
730    
731        /**
732         * Append a double value. This increases the array's length by one.
733         *
734         * @param value A double value.
735         *
736         * @return this.
737         *
738         * @throws JSONException if the value is not finite.
739         */
740        public JSONArray put(Double value) throws JSONException
741        {
742            JSONObject.testValidity(value);
743            put(value);
744            return this;
745        }
746    
747    
748        /**
749         * Append an int value. This increases the array's length by one.
750         *
751         * @param value An int value.
752         *
753         * @return this.
754         */
755        public JSONArray put(int value)
756        {
757            put(new Integer(value));
758            return this;
759        }
760    
761    
762        /**
763         * Append an long value. This increases the array's length by one.
764         *
765         * @param value A long value.
766         *
767         * @return this.
768         */
769        public JSONArray put(long value)
770        {
771            put(new Long(value));
772            return this;
773        }
774    
775    
776        /**
777         * Put a value in the JSONArray, where the value will be a
778         * JSONObject which is produced from a Map.
779         *
780         * @param value A Map value.
781         *
782         * @return this.
783         */
784        public JSONArray put(Map value)
785        {
786            put(new JSONObject(value));
787            return this;
788        }
789    
790    
791        /**
792         * Append an object value. This increases the array's length by one.
793         *
794         * @param value An object value.  The value should be a
795         *              Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
796         *              JSONObject.NULL object.
797         *
798         * @return this.
799         */
800        public JSONArray put(Object value)
801        {
802            this.myArrayList.add(value);
803            return this;
804        }
805    
806    
807        /**
808         * Put or replace a boolean value in the JSONArray. If the index is greater
809         * than the length of the JSONArray, then null elements will be added as
810         * necessary to pad it out.
811         *
812         * @param index The subscript.
813         * @param value A boolean value.
814         *
815         * @return this.
816         *
817         * @throws JSONException If the index is negative.
818         */
819        public JSONArray put(int index, boolean value) throws JSONException
820        {
821            put(index, value ? Boolean.TRUE : Boolean.FALSE);
822            return this;
823        }
824    
825    
826        /**
827         * Put a value in the JSONArray, where the value will be a
828         * JSONArray which is produced from a Collection.
829         *
830         * @param index The subscript.
831         * @param value A Collection value.
832         *
833         * @return this.
834         *
835         * @throws JSONException If the index is negative or if the value is
836         *                       not finite.
837         */
838        public JSONArray put(int index, Collection value) throws JSONException
839        {
840            put(index, new JSONArray(value));
841            return this;
842        }
843    
844    
845        /**
846         * Put or replace a double value. If the index is greater than the length of
847         * the JSONArray, then null elements will be added as necessary to pad
848         * it out.
849         *
850         * @param index The subscript.
851         * @param value A double value.
852         *
853         * @return this.
854         *
855         * @throws JSONException If the index is negative or if the value is
856         *                       not finite.
857         */
858        public JSONArray put(int index, double value) throws JSONException
859        {
860            put(index, new Double(value));
861            return this;
862        }
863    
864    
865        /**
866         * Put or replace an int value. If the index is greater than the length of
867         * the JSONArray, then null elements will be added as necessary to pad
868         * it out.
869         *
870         * @param index The subscript.
871         * @param value An int value.
872         *
873         * @return this.
874         *
875         * @throws JSONException If the index is negative.
876         */
877        public JSONArray put(int index, int value) throws JSONException
878        {
879            put(index, new Integer(value));
880            return this;
881        }
882    
883    
884        /**
885         * Put or replace a long value. If the index is greater than the length of
886         * the JSONArray, then null elements will be added as necessary to pad
887         * it out.
888         *
889         * @param index The subscript.
890         * @param value A long value.
891         *
892         * @return this.
893         *
894         * @throws JSONException If the index is negative.
895         */
896        public JSONArray put(int index, long value) throws JSONException
897        {
898            put(index, new Long(value));
899            return this;
900        }
901    
902    
903        /**
904         * Put a value in the JSONArray, where the value will be a
905         * JSONObject which is produced from a Map.
906         *
907         * @param index The subscript.
908         * @param value The Map value.
909         *
910         * @return this.
911         *
912         * @throws JSONException If the index is negative or if the the value is
913         *                       an invalid number.
914         */
915        public JSONArray put(int index, Map value) throws JSONException
916        {
917            put(index, new JSONObject(value));
918            return this;
919        }
920    
921    
922        /**
923         * Put or replace an object value in the JSONArray. If the index is greater
924         * than the length of the JSONArray, then null elements will be added as
925         * necessary to pad it out.
926         *
927         * @param index The subscript.
928         * @param value The value to put into the array. The value should be a
929         *              Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
930         *              JSONObject.NULL object.
931         *
932         * @return this.
933         *
934         * @throws JSONException If the index is negative or if the the value is
935         *                       an invalid number.
936         */
937        public JSONArray put(int index, Object value) throws JSONException
938        {
939            JSONObject.testValidity(value);
940            if (index < 0)
941            {
942                throw new JSONException("JSONArray[" + index + "] not found.");
943            }
944            if (index < length())
945            {
946                this.myArrayList.set(index, value);
947            }
948            else
949            {
950                while (index != length())
951                {
952                    put(JSONObject.NULL);
953                }
954                put(value);
955            }
956            return this;
957        }
958    
959    
960        /**
961         * Produce a JSONObject by combining a JSONArray of names with the values
962         * of this JSONArray.
963         *
964         * @param names A JSONArray containing a list of key strings. These will be
965         *              paired with the values.
966         *
967         * @return A JSONObject, or null if there are no names or if this JSONArray
968         *         has no values.
969         *
970         * @throws JSONException If any of the names are null.
971         */
972        public JSONObject toJSONObject(JSONArray names) throws JSONException
973        {
974            if (names == null || names.length() == 0 || length() == 0)
975            {
976                return null;
977            }
978            JSONObject jo = new JSONObject();
979            for (int i = 0; i < names.length(); i += 1)
980            {
981                jo.put(names.getString(i), this.opt(i));
982            }
983            return jo;
984        }
985    
986    
987        /**
988         * Make a JSON text of this JSONArray. For compactness, no
989         * unnecessary whitespace is added. If it is not possible to produce a
990         * syntactically correct JSON text then null will be returned instead. This
991         * could occur if the array contains an invalid number.
992         * <p/>
993         * Warning: This method assumes that the data structure is acyclical.
994         *
995         * @return a printable, displayable, transmittable
996         *         representation of the array.
997         */
998        public String toString()
999        {
1000            try
1001            {
1002                return '[' + join(",") + ']';
1003            }
1004            catch (Exception e)
1005            {
1006                return null;
1007            }
1008        }
1009    
1010    
1011        /**
1012         * Make a prettyprinted JSON text of this JSONArray.
1013         * Warning: This method assumes that the data structure is acyclical.
1014         *
1015         * @param indentFactor The number of spaces to add to each level of
1016         *                     indentation.
1017         *
1018         * @return a printable, displayable, transmittable
1019         *         representation of the object, beginning
1020         *         with <code>[</code>&nbsp;<small>(left bracket)</small> and ending
1021         *         with <code>]</code>&nbsp;<small>(right bracket)</small>.
1022         *
1023         * @throws JSONException
1024         */
1025        public String toString(int indentFactor) throws JSONException
1026        {
1027            return toString(indentFactor, 0);
1028        }
1029    
1030    
1031        /**
1032         * Make a prettyprinted JSON text of this JSONArray.
1033         * Warning: This method assumes that the data structure is acyclical.
1034         *
1035         * @param indentFactor The number of spaces to add to each level of
1036         *                     indentation.
1037         * @param indent       The indention of the top level.
1038         *
1039         * @return a printable, displayable, transmittable
1040         *         representation of the array.
1041         *
1042         * @throws JSONException
1043         */
1044        String toString(int indentFactor, int indent) throws JSONException
1045        {
1046            int len = length();
1047            if (len == 0)
1048            {
1049                return "[]";
1050            }
1051            int i;
1052            StringBuffer sb = new StringBuffer("[");
1053            if (len == 1)
1054            {
1055                sb.append(JSONObject.valueToString(this.myArrayList.get(0),
1056                                                   indentFactor, indent));
1057            }
1058            else
1059            {
1060                int newindent = indent + indentFactor;
1061                sb.append('\n');
1062                for (i = 0; i < len; i += 1)
1063                {
1064                    if (i > 0)
1065                    {
1066                        sb.append(",\n");
1067                    }
1068                    for (int j = 0; j < newindent; j += 1)
1069                    {
1070                        sb.append(' ');
1071                    }
1072                    sb.append(JSONObject.valueToString(this.myArrayList.get(i),
1073                                                       indentFactor, newindent));
1074                }
1075                sb.append('\n');
1076                for (i = 0; i < indent; i += 1)
1077                {
1078                    sb.append(' ');
1079                }
1080            }
1081            sb.append(']');
1082            return sb.toString();
1083        }
1084    
1085    
1086        /**
1087         * Write the contents of the JSONArray as JSON text to a writer.
1088         * For compactness, no whitespace is added.
1089         * <p/>
1090         * Warning: This method assumes that the data structure is acyclical.
1091         *
1092         * @return The writer.
1093         *
1094         * @throws JSONException
1095         */
1096        public Writer write(Writer writer) throws JSONException
1097        {
1098            try
1099            {
1100                boolean b = false;
1101                int len = length();
1102    
1103                writer.write('[');
1104    
1105                for (int i = 0; i < len; i += 1)
1106                {
1107                    if (b)
1108                    {
1109                        writer.write(',');
1110                    }
1111                    Object v = this.myArrayList.get(i);
1112                    if (v instanceof JSONObject)
1113                    {
1114                        ((JSONObject) v).write(writer);
1115                    }
1116                    else if (v instanceof JSONArray)
1117                    {
1118                        ((JSONArray) v).write(writer);
1119                    }
1120                    else
1121                    {
1122                        writer.write(JSONObject.valueToString(v));
1123                    }
1124                    b = true;
1125                }
1126                writer.write(']');
1127                return writer;
1128            }
1129            catch (IOException e)
1130            {
1131                throw new JSONException(e);
1132            }
1133        }
1134    }