1package com.xtremelabs.robolectric.shadows;
2
3import static com.xtremelabs.robolectric.Robolectric.shadowOf;
4
5import android.os.Bundle;
6import android.os.Parcel;
7import android.os.Parcelable;
8import android.text.TextUtils;
9import android.util.Log;
10import android.util.Pair;
11
12import com.xtremelabs.robolectric.Robolectric;
13import com.xtremelabs.robolectric.bytecode.ShadowWrangler;
14import com.xtremelabs.robolectric.internal.Implementation;
15import com.xtremelabs.robolectric.internal.Implements;
16import com.xtremelabs.robolectric.internal.RealObject;
17
18import java.lang.reflect.Field;
19import java.util.ArrayList;
20import java.util.HashMap;
21import java.util.List;
22import java.util.Map;
23import java.util.Set;
24
25@Implements(Parcel.class)
26@SuppressWarnings("unchecked")
27public class ShadowParcel {
28
29    private static final int VAL_NULL = -1;
30    private static final int VAL_STRING = 0;
31    private static final int VAL_INTEGER = 1;
32    private static final int VAL_MAP = 2;
33    private static final int VAL_BUNDLE = 3;
34    private static final int VAL_PARCELABLE = 4;
35    private static final int VAL_SHORT = 5;
36    private static final int VAL_LONG = 6;
37    private static final int VAL_FLOAT = 7;
38    private static final int VAL_DOUBLE = 8;
39    private static final int VAL_BOOLEAN = 9;
40    private static final int VAL_CHARSEQUENCE = 10;
41    private static final int VAL_LIST = 11;
42    private static final int VAL_BYTEARRAY = 13;
43    private static final int VAL_STRINGARRAY = 14;
44    private static final int VAL_PARCELABLEARRAY = 16;
45    private static final int VAL_OBJECTARRAY = 17;
46    private static final int VAL_INTARRAY = 18;
47    private static final int VAL_LONGARRAY = 19;
48    private static final int VAL_BYTE = 20;
49    private static final int VAL_BOOLEANARRAY = 23;
50    private static final int VAL_CHARSEQUENCEARRAY = 24;
51
52    private final ArrayList<Pair<Integer, ?>> parcelData = new ArrayList<Pair<Integer, ?>>();
53    private int index = 0;
54
55    @RealObject
56    private Parcel realParcel;
57
58    @Implementation
59    public static Parcel obtain() {
60        return Robolectric.newInstanceOf(Parcel.class);
61    }
62
63    @Implementation
64    public int dataAvail() {
65        return dataSize() - dataPosition();
66    }
67
68    @Implementation
69    public int dataPosition() {
70        return calculateSizeToIndex(index);
71    }
72
73    @Implementation
74    public int dataSize() {
75        return calculateSizeToIndex(parcelData.size());
76    }
77
78    @Implementation
79    public int dataCapacity() {
80        return dataSize();
81    }
82
83    @Implementation
84    public void setDataPosition(int pos) {
85        index = calculateIndexFromSizePosition(pos);
86    }
87
88    private int calculateSizeToIndex(int index) {
89        int size = 0;
90        for (int i = 0; i < index; i++) {
91            size += parcelData.get(i).first;
92        }
93        return size;
94    }
95
96    private int calculateIndexFromSizePosition(int pos) {
97        int size = 0;
98        for (int i = 0; i < parcelData.size(); i++) {
99            if (size >= pos) {
100                return i;
101            }
102            size += parcelData.get(i).first;
103        }
104        return parcelData.size();
105    }
106
107    @Implementation
108    public void writeString(String str) {
109        if (str == null) {
110            writeInt(-1);
111        } else {
112            writeInt(str.length());
113            addValueToList(Pair.create(str.length(), str));
114        }
115    }
116
117    @Implementation
118    public String readString() {
119        int N = readInt();
120        if (N < 0) {
121            return null;
122        } else {
123            return readValueFromList(null);
124        }
125    }
126
127    @Implementation
128    public CharSequence readCharSequence() {
129        return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(realParcel);
130    }
131
132    @Implementation
133    public void writeCharSequence(CharSequence val) {
134        TextUtils.writeToParcel(val, realParcel, 0);
135    }
136
137    @Implementation
138    public void writeInt(int i) {
139        addValueToList(Pair.create(Integer.SIZE / 8, i));
140    }
141
142    @Implementation
143    public int readInt() {
144        return readValueFromList(0);
145    }
146
147    @Implementation
148    public void writeLong(long i) {
149        addValueToList(Pair.create(Long.SIZE / 8, i));
150    }
151
152    @Implementation
153    public long readLong() {
154        return readValueFromList((long) 0);
155    }
156
157    @Implementation
158    public void writeFloat(float f) {
159        addValueToList(Pair.create(Float.SIZE / 8, f));
160    }
161
162    @Implementation
163    public float readFloat() {
164        return readValueFromList((float) 0);
165    }
166
167    @Implementation
168    public void writeDouble(double f) {
169        addValueToList(Pair.create(Double.SIZE / 8, f));
170    }
171
172    @Implementation
173    public double readDouble() {
174        return readValueFromList((double) 0);
175    }
176
177    public void writeBoolean(boolean b) {
178        addValueToList(Pair.create(1, b));
179    }
180
181    public boolean readBoolean() {
182        return readValueFromList(false);
183    }
184
185    public void writeChar(char c) {
186        addValueToList(Pair.create(Character.SIZE / 8, c));
187    }
188
189    public char readChar() {
190        return readValueFromList((char) 0);
191    }
192
193    @Implementation
194    @SuppressWarnings("unchecked")
195    public void writeByte(byte b) {
196        addValueToList(Pair.create(Byte.SIZE / 8, b));
197    }
198
199    @Implementation
200    public byte readByte() {
201        return readValueFromList((byte) 0);
202    }
203
204    @Implementation
205    public void readBooleanArray(boolean[] val) {
206        int N = readInt();
207        if (val.length != N)
208            throw new RuntimeException("bad array lengths");
209        for (int i = 0; i < val.length; i++) {
210            val[i] = readBoolean();
211        }
212    }
213
214    @Implementation
215    public void writeBooleanArray(boolean[] val) {
216        if (val == null) {
217            writeInt(-1);
218            return;
219        }
220        writeInt(val.length);
221        for (boolean b : val)
222            writeBoolean(b);
223    }
224
225    @Implementation
226    public boolean[] createBooleanArray() {
227        int N = readInt();
228        if (N < 0) {
229            return null;
230        }
231        boolean[] val = new boolean[N];
232        for (int i = 0; i < val.length; i++) {
233            val[i] = readBoolean();
234        }
235        return val;
236    }
237
238    @Implementation
239    public void readCharArray(char[] val) {
240        int N = readInt();
241        if (val.length != N)
242            throw new RuntimeException("bad array lengths");
243        for (int i = 0; i < val.length; i++) {
244            val[i] = readChar();
245        }
246    }
247
248    @Implementation
249    public void writeCharArray(char[] val) {
250        if (val == null) {
251            writeInt(-1);
252            return;
253        }
254        writeInt(val.length);
255        for (char b : val)
256            writeChar(b);
257    }
258
259    @Implementation
260    public char[] createCharArray() {
261        int N = readInt();
262        if (N < 0) {
263            return null;
264        }
265        char[] val = new char[N];
266        for (int i = 0; i < val.length; i++) {
267            val[i] = readChar();
268        }
269        return val;
270    }
271
272    @Implementation
273    public void readFloatArray(float[] val) {
274        int N = readInt();
275        if (val.length != N)
276            throw new RuntimeException("bad array lengths");
277        for (int i = 0; i < val.length; i++) {
278            val[i] = readFloat();
279        }
280    }
281
282    @Implementation
283    public void writeFloatArray(float[] val) {
284        if (val == null) {
285            writeInt(-1);
286            return;
287        }
288        writeInt(val.length);
289        for (float f : val)
290            writeFloat(f);
291    }
292
293    @Implementation
294    public float[] createFloatArray() {
295        int N = readInt();
296        if (N < 0) {
297            return null;
298        }
299        float[] val = new float[N];
300        for (int i = 0; i < val.length; i++) {
301            val[i] = readFloat();
302        }
303        return val;
304    }
305
306    @Implementation
307    public void writeDoubleArray(double[] val) {
308        if (val == null) {
309            writeInt(-1);
310            return;
311        }
312        writeInt(val.length);
313        for (double f : val)
314            writeDouble(f);
315    }
316
317    @Implementation
318    public void readDoubleArray(double[] val) {
319        int N = readInt();
320        if (val.length != N)
321            throw new RuntimeException("bad array lengths");
322        for (int i = 0; i < val.length; i++) {
323            val[i] = readDouble();
324        }
325    }
326
327    @Implementation
328    public double[] createDoubleArray() {
329        int N = readInt();
330        if (N < 0) {
331            return null;
332        }
333        double[] val = new double[N];
334        for (int i = 0; i < val.length; i++) {
335            val[i] = readDouble();
336        }
337        return val;
338    }
339
340    @Implementation
341    public void writeIntArray(int[] val) {
342        if (val == null) {
343            writeInt(-1);
344            return;
345        }
346        writeInt(val.length);
347        for (int f : val)
348            writeInt(f);
349    }
350
351    @Implementation
352    public void readIntArray(int[] val) {
353        int N = readInt();
354        if (val.length != N)
355            throw new RuntimeException("bad array lengths");
356        for (int i = 0; i < val.length; i++) {
357            val[i] = readInt();
358        }
359    }
360
361    @Implementation
362    public int[] createIntArray() {
363        int N = readInt();
364        if (N < 0) {
365            return null;
366        }
367        int[] val = new int[N];
368        for (int i = 0; i < val.length; i++) {
369            val[i] = readInt();
370        }
371        return val;
372    }
373
374    @Implementation
375    public void writeByteArray(byte[] val) {
376        if (val == null) {
377            writeInt(-1);
378            return;
379        }
380        writeInt(val.length);
381        for (byte f : val)
382            writeByte(f);
383    }
384
385    @Implementation
386    public void readByteArray(byte[] val) {
387        int N = readInt();
388        if (val.length != N)
389            throw new RuntimeException("bad array lengths");
390        for (int i = 0; i < val.length; i++) {
391            val[i] = readByte();
392        }
393    }
394
395    @Implementation
396    public byte[] createByteArray() {
397        int N = readInt();
398        if (N < 0) {
399            return null;
400        }
401        byte[] val = new byte[N];
402        for (int i = 0; i < val.length; i++) {
403            val[i] = readByte();
404        }
405        return val;
406    }
407
408    @Implementation
409    public void writeLongArray(long[] val) {
410        if (val == null) {
411            writeInt(-1);
412            return;
413        }
414        writeInt(val.length);
415        for (long f : val)
416            writeLong(f);
417    }
418
419    @Implementation
420    public void readLongArray(long[] val) {
421        int N = readInt();
422        if (val.length != N)
423            throw new RuntimeException("bad array lengths");
424        for (int i = 0; i < val.length; i++) {
425            val[i] = readLong();
426        }
427    }
428
429    @Implementation
430    public long[] createLongArray() {
431        int N = readInt();
432        if (N < 0) {
433            return null;
434        }
435        long[] val = new long[N];
436        for (int i = 0; i < val.length; i++) {
437            val[i] = readLong();
438        }
439        return val;
440    }
441
442    @Implementation
443    public void writeStringArray(String[] val) {
444        if (val == null) {
445            writeInt(-1);
446            return;
447        }
448        writeInt(val.length);
449        for (String f : val)
450            writeString(f);
451    }
452
453    @Implementation
454    public String[] createStringArray() {
455        String[] array = null;
456
457        int N = readInt();
458        if (N >= 0) {
459            array = new String[N];
460            for (int i = 0; i < N; i++) {
461                array[i] = readString();
462            }
463        }
464        return array;
465    }
466
467    @Implementation
468    public void readStringArray(String[] dest) {
469        int N = readInt();
470        if (dest.length != N)
471            throw new RuntimeException("bad array lengths");
472        for (int i = 0; i < dest.length; i++) {
473            dest[i] = readString();
474        }
475    }
476
477    @Implementation
478    public void writeStringList(List<String> strings) {
479        if (strings == null) {
480            writeInt(-1);
481            return;
482        }
483        int count = strings.size();
484        int i = 0;
485        writeInt(count);
486        while (i < count) {
487            writeString(strings.get(i));
488            i++;
489        }
490    }
491
492    @Implementation
493    public void readStringList(List<String> list) {
494        int listSizeBeforeChange = list.size();
495        int addCount = readInt();
496        int i = 0;
497        for (; i < listSizeBeforeChange && i < addCount; i++) {
498            list.set(i, readString());
499        }
500        for (; i < addCount; i++) {
501            list.add(readString());
502        }
503        for (; i < listSizeBeforeChange; i++) {
504            list.remove(addCount);
505        }
506    }
507
508    @Implementation
509    public ArrayList<String> createStringArrayList() {
510        int N = readInt();
511        if (N < 0) {
512            return null;
513        }
514
515        ArrayList<String> l = new ArrayList<String>(N);
516        while (N > 0) {
517            l.add(readString());
518            N--;
519        }
520        return l;
521    }
522
523    @Implementation
524    public void writeCharSequenceArray(CharSequence[] val) {
525        if (val != null) {
526            int N = val.length;
527            writeInt(N);
528            for (int i=0; i<N; i++) {
529                writeCharSequence(val[i]);
530            }
531        } else {
532            writeInt(-1);
533        }
534    }
535
536    @Implementation
537    public CharSequence[] readCharSequenceArray() {
538        CharSequence[] array = null;
539
540        int length = readInt();
541        if (length >= 0)
542        {
543            array = new CharSequence[length];
544
545            for (int i = 0 ; i < length ; i++)
546            {
547                array[i] = readCharSequence();
548            }
549        }
550
551        return array;
552    }
553
554    @Implementation
555    public void writeList(List val) {
556        if (val == null) {
557            writeInt(-1);
558            return;
559        }
560        int N = val.size();
561        int i = 0;
562        writeInt(N);
563        while (i < N) {
564            writeValue(val.get(i));
565            i++;
566        }
567    }
568
569    @Implementation
570    public void readList(List outVal, ClassLoader loader) {
571        int N = readInt();
572        readListInternal(outVal, N, loader);
573    }
574
575    @Implementation
576    public ArrayList readArrayList(ClassLoader loader) {
577        int N = readInt();
578        if (N < 0) {
579            return null;
580        }
581        ArrayList l = new ArrayList(N);
582        readListInternal(l, N, loader);
583        return l;
584    }
585
586    @Implementation
587    public void writeArray(Object[] values) {
588        if (values == null) {
589            writeInt(-1);
590            return;
591        }
592        int N = values.length;
593        writeInt(N);
594        for (Object value : values) {
595            writeValue(value);
596        }
597    }
598
599    @Implementation
600    public Object[] readArray(ClassLoader loader) {
601        int N = readInt();
602        if (N < 0) {
603            return null;
604        }
605        Object[] l = new Object[N];
606        readArrayInternal(l, N, loader);
607        return l;
608    }
609
610    @Implementation
611    public void writeValue(Object v) {
612        if (v == null) {
613            writeInt(VAL_NULL);
614        } else if (v instanceof String) {
615            writeInt(VAL_STRING);
616            writeString((String) v);
617        } else if (v instanceof Integer) {
618            writeInt(VAL_INTEGER);
619            writeInt((Integer) v);
620        } else if (v instanceof Map) {
621            writeInt(VAL_MAP);
622            writeMap((Map) v);
623        } else if (v instanceof Bundle) {
624            // Must be before Parcelable
625            writeInt(VAL_BUNDLE);
626            writeBundle((Bundle) v);
627        } else if (v instanceof Parcelable) {
628            writeInt(VAL_PARCELABLE);
629            writeParcelable((Parcelable) v, 0);
630        } else if (v instanceof Short) {
631            writeInt(VAL_SHORT);
632            writeInt(((Short) v).intValue());
633        } else if (v instanceof Long) {
634            writeInt(VAL_LONG);
635            writeLong((Long) v);
636        } else if (v instanceof Float) {
637            writeInt(VAL_FLOAT);
638            writeFloat((Float) v);
639        } else if (v instanceof Double) {
640            writeInt(VAL_DOUBLE);
641            writeDouble((Double) v);
642        } else if (v instanceof Boolean) {
643            writeInt(VAL_BOOLEAN);
644            writeInt((Boolean) v ? 1 : 0);
645        } else if (v instanceof CharSequence) {
646            // Must be after String
647            writeInt(VAL_CHARSEQUENCE);
648            writeCharSequence((CharSequence) v);
649        } else if (v instanceof List) {
650            writeInt(VAL_LIST);
651            writeList((List) v);
652        } else if (v instanceof boolean[]) {
653            writeInt(VAL_BOOLEANARRAY);
654            writeBooleanArray((boolean[]) v);
655        } else if (v instanceof byte[]) {
656            writeInt(VAL_BYTEARRAY);
657            writeByteArray((byte[]) v);
658        } else if (v instanceof String[]) {
659            writeInt(VAL_STRINGARRAY);
660            writeStringArray((String[]) v);
661        } else if (v instanceof CharSequence[]) {
662            // Must be after String[] and before Object[]
663            writeInt(VAL_CHARSEQUENCEARRAY);
664            writeCharSequenceArray((CharSequence[]) v);
665        } else if (v instanceof Parcelable[]) {
666            writeInt(VAL_PARCELABLEARRAY);
667            writeParcelableArray((Parcelable[]) v, 0);
668        } else if (v instanceof Object[]) {
669            writeInt(VAL_OBJECTARRAY);
670            writeArray((Object[]) v);
671        } else if (v instanceof int[]) {
672            writeInt(VAL_INTARRAY);
673            writeIntArray((int[]) v);
674        } else if (v instanceof long[]) {
675            writeInt(VAL_LONGARRAY);
676            writeLongArray((long[]) v);
677        } else if (v instanceof Byte) {
678            writeInt(VAL_BYTE);
679            writeByte((Byte) v);
680        } else {
681            throw new RuntimeException(
682                    "Parcel: unable to marshal value with type" + v.getClass().getName());
683        }
684    }
685
686    @Implementation
687    public Object readValue(ClassLoader loader) {
688        int type = readInt();
689
690        switch (type) {
691            case VAL_NULL:
692                return null;
693
694            case VAL_STRING:
695                return readString();
696
697            case VAL_INTEGER:
698                return readInt();
699
700            case VAL_MAP:
701                return readHashMap(loader);
702
703            case VAL_PARCELABLE:
704                return readParcelable(loader);
705
706            case VAL_SHORT:
707                return (short) readInt();
708
709            case VAL_LONG:
710                return readLong();
711
712            case VAL_FLOAT:
713                return readFloat();
714
715            case VAL_DOUBLE:
716                return readDouble();
717
718            case VAL_BOOLEAN:
719                return readInt() == 1;
720
721            case VAL_CHARSEQUENCE:
722                return readCharSequence();
723
724            case VAL_LIST:
725                return readArrayList(loader);
726
727            case VAL_BOOLEANARRAY:
728                return createBooleanArray();
729
730            case VAL_BYTEARRAY:
731                return createByteArray();
732
733            case VAL_STRINGARRAY:
734                return createStringArray();
735
736            case VAL_CHARSEQUENCEARRAY:
737                return readCharSequenceArray();
738
739            case VAL_OBJECTARRAY:
740                return readArray(loader);
741
742            case VAL_INTARRAY:
743                return createIntArray();
744
745            case VAL_LONGARRAY:
746                return createLongArray();
747
748            case VAL_BYTE:
749                return readByte();
750
751            case VAL_PARCELABLEARRAY:
752                return readParcelableArray(loader);
753
754            case VAL_BUNDLE:
755                return readBundle(loader); // loading will be deferred
756
757            default:
758                int off = dataPosition() - 4;
759                throw new RuntimeException(
760                        "Parcel " + this + ": Unmarshalling unknown type code " + type
761                        + " at offset " + off);
762        }
763    }
764
765    @Implementation
766    public Bundle readBundle() {
767        return readBundle(null);
768    }
769
770    @Implementation
771    public Bundle readBundle(ClassLoader loader) {
772        int offset = dataPosition();
773        int N = readInt();
774        if (N < 0) {
775            return null;
776        }
777        int magic = readInt();
778        if (magic != 0x4C444E42) {
779            throw new RuntimeException("Magic number missing from bundle stream");
780        }
781
782        Bundle bundle = new Bundle();
783
784        // Read map
785        HashMap m = new HashMap();
786        readMap(m, null);
787
788        shadowOf(bundle).map.putAll(m);
789
790        return bundle;
791    }
792
793    @Implementation
794    public void writeBundle(Bundle val) {
795        if (val == null) {
796            writeInt(-1);
797            return;
798        }
799
800        writeInt(-1); // dummy, will hold length
801        int oldPos = dataPosition();
802        writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
803
804        writeMapInternal(shadowOf(val).map);
805        int newPos = dataPosition();
806
807        // Backpatch length
808        setDataPosition(oldPos - 4);
809        int N = newPos - oldPos;
810        writeInt(N);
811        setDataPosition(newPos);
812    }
813
814    @Implementation
815    public void writeParcelable(Parcelable p, int flags) {
816        if (p == null) {
817            writeString(null);
818            return;
819        }
820        String name = p.getClass().getName();
821        writeString(name);
822        p.writeToParcel(realParcel, flags);
823    }
824
825    @Implementation
826    public <T extends Parcelable> T readParcelable(ClassLoader loader) {
827        String name = readString();
828        if (name == null) {
829            return null;
830        }
831        Parcelable.Creator<T> creator;
832        try {
833            Class c = loader == null ? Class.forName(name) : Class.forName(name, true, loader);
834            Field f = c.getField("CREATOR");
835            creator = (Parcelable.Creator) f.get(null);
836        } catch (IllegalAccessException e) {
837            Log.e("Parcel", "Class not found when unmarshalling: " + name + ", e: " + e);
838            throw new RuntimeException("IllegalAccessException when unmarshalling: " + name);
839        } catch (ClassNotFoundException e) {
840            Log.e("Parcel", "Class not found when unmarshalling: " + name + ", e: " + e);
841            throw new RuntimeException("ClassNotFoundException when unmarshalling: " + name);
842        } catch (ClassCastException e) {
843            throw new RuntimeException("Parcelable protocol requires a "
844                    + "Parcelable.Creator object called " + " CREATOR on class " + name);
845        } catch (NoSuchFieldException e) {
846            throw new RuntimeException("Parcelable protocol requires a "
847                    + "Parcelable.Creator object called " + " CREATOR on class " + name);
848        }
849        if (creator == null) {
850            throw new RuntimeException("Parcelable protocol requires a "
851                    + "Parcelable.Creator object called " + " CREATOR on class " + name);
852        }
853
854        return creator.createFromParcel(realParcel);
855    }
856
857    @Implementation
858    public ArrayList createTypedArrayList(Parcelable.Creator c) {
859        int N = readInt();
860        if (N < 0) {
861            return null;
862        }
863
864        ArrayList l = new ArrayList(N);
865
866        while (N > 0) {
867            if (readInt() != 0) {
868                l.add(c.createFromParcel(realParcel));
869            } else {
870                l.add(null);
871            }
872            N--;
873        }
874        return l;
875    }
876
877    @Implementation
878    public void writeTypedList(List val) {
879        if (val == null) {
880            writeInt(-1);
881            return;
882        }
883
884        int N = val.size();
885        int i = 0;
886        writeInt(N);
887        while (i < N) {
888            Object item = val.get(i);
889            if (item != null) {
890                writeInt(1);
891                ((Parcelable) item).writeToParcel(realParcel, 0);
892            } else {
893                writeInt(0);
894            }
895            i++;
896        }
897    }
898
899    @Implementation
900    public <T extends Parcelable> void writeParcelableArray(T[] value,
901            int parcelableFlags) {
902        if (value != null) {
903            int N = value.length;
904            writeInt(N);
905            for (int i=0; i<N; i++) {
906                writeParcelable(value[i], parcelableFlags);
907            }
908        } else {
909            writeInt(-1);
910        }
911    }
912
913    @Implementation
914    public Parcelable[] readParcelableArray(ClassLoader loader) {
915        int N = readInt();
916        if (N < 0) {
917            return null;
918        }
919        Parcelable[] p = new Parcelable[N];
920        for (int i = 0; i < N; i++) {
921            p[i] = readParcelable(loader);
922        }
923        return p;
924    }
925
926    @Implementation
927    public void writeMap(Map val) {
928        writeMapInternal(val);
929    }
930
931    @Implementation
932    public void readMap(Map outVal, ClassLoader loader) {
933        int N = readInt();
934        readMapInternal(outVal, N, loader);
935    }
936
937    @Implementation
938    public HashMap readHashMap(ClassLoader loader) {
939        int N = readInt();
940        if (N < 0) {
941            return null;
942        }
943        HashMap m = new HashMap(N);
944        readMapInternal(m, N, loader);
945        return m;
946    }
947
948    private void writeMapInternal(Map<String, Object> val) {
949        if (val == null) {
950            writeInt(-1);
951            return;
952        }
953
954        Set<Map.Entry<String, Object>> entries = val.entrySet();
955        writeInt(entries.size());
956        for (Map.Entry<String, Object> e : entries) {
957            writeValue(e.getKey());
958            writeValue(e.getValue());
959        }
960    }
961
962    private void readMapInternal(Map outVal, int N, ClassLoader loader) {
963        for (int i = 0; i < N; i++) {
964            Object key = readValue(loader);
965            Object value = readValue(loader);
966            outVal.put(key, value);
967        }
968    }
969
970    private void readListInternal(List outVal, int N, ClassLoader loader) {
971        while (N > 0) {
972            Object value = readValue(loader);
973            outVal.add(value);
974            N--;
975        }
976    }
977
978    private void readArrayInternal(Object[] outVal, int N, ClassLoader loader) {
979        for (int i = 0; i < N; i++) {
980            Object value = readValue(loader);
981            outVal[i] = value;
982        }
983    }
984
985    private void addValueToList(Pair<Integer, ?> value) {
986        if (index < parcelData.size()) {
987            parcelData.set(index, value);
988        } else {
989            parcelData.add(value);
990        }
991        index++;
992    }
993
994    private <T extends Object> T readValueFromList(T defaultValue) {
995        if (index < parcelData.size()) {
996            return (T) parcelData.get(index++).second;
997        } else {
998            return defaultValue;
999        }
1000    }
1001
1002    public int getIndex() {
1003        return index;
1004    }
1005
1006    public List getParcelData() {
1007        return parcelData;
1008    }
1009}
1010