XmlUtils.java revision 73bdf9761be2abdd85efc5fce165f3fa80fcfa65
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.util;
18
19import android.graphics.Bitmap;
20import android.graphics.BitmapFactory;
21import android.graphics.Bitmap.CompressFormat;
22import android.net.Uri;
23import android.util.Base64;
24import android.util.Xml;
25
26import org.xmlpull.v1.XmlPullParser;
27import org.xmlpull.v1.XmlPullParserException;
28import org.xmlpull.v1.XmlSerializer;
29
30import java.io.ByteArrayOutputStream;
31import java.io.IOException;
32import java.io.InputStream;
33import java.io.OutputStream;
34import java.net.ProtocolException;
35import java.util.ArrayList;
36import java.util.HashMap;
37import java.util.HashSet;
38import java.util.Iterator;
39import java.util.List;
40import java.util.Map;
41import java.util.Set;
42
43/** {@hide} */
44public class XmlUtils {
45
46    public static void skipCurrentTag(XmlPullParser parser)
47            throws XmlPullParserException, IOException {
48        int outerDepth = parser.getDepth();
49        int type;
50        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
51               && (type != XmlPullParser.END_TAG
52                       || parser.getDepth() > outerDepth)) {
53        }
54    }
55
56    public static final int
57    convertValueToList(CharSequence value, String[] options, int defaultValue)
58    {
59        if (null != value) {
60            for (int i = 0; i < options.length; i++) {
61                if (value.equals(options[i]))
62                    return i;
63            }
64        }
65
66        return defaultValue;
67    }
68
69    public static final boolean
70    convertValueToBoolean(CharSequence value, boolean defaultValue)
71    {
72        boolean result = false;
73
74        if (null == value)
75            return defaultValue;
76
77        if (value.equals("1")
78        ||  value.equals("true")
79        ||  value.equals("TRUE"))
80            result = true;
81
82        return result;
83    }
84
85    public static final int
86    convertValueToInt(CharSequence charSeq, int defaultValue)
87    {
88        if (null == charSeq)
89            return defaultValue;
90
91        String nm = charSeq.toString();
92
93        // XXX This code is copied from Integer.decode() so we don't
94        // have to instantiate an Integer!
95
96        int value;
97        int sign = 1;
98        int index = 0;
99        int len = nm.length();
100        int base = 10;
101
102        if ('-' == nm.charAt(0)) {
103            sign = -1;
104            index++;
105        }
106
107        if ('0' == nm.charAt(index)) {
108            //  Quick check for a zero by itself
109            if (index == (len - 1))
110                return 0;
111
112            char    c = nm.charAt(index + 1);
113
114            if ('x' == c || 'X' == c) {
115                index += 2;
116                base = 16;
117            } else {
118                index++;
119                base = 8;
120            }
121        }
122        else if ('#' == nm.charAt(index))
123        {
124            index++;
125            base = 16;
126        }
127
128        return Integer.parseInt(nm.substring(index), base) * sign;
129    }
130
131    public static int convertValueToUnsignedInt(String value, int defaultValue) {
132        if (null == value) {
133            return defaultValue;
134        }
135
136        return parseUnsignedIntAttribute(value);
137    }
138
139    public static int parseUnsignedIntAttribute(CharSequence charSeq) {
140        String  value = charSeq.toString();
141
142        long    bits;
143        int     index = 0;
144        int     len = value.length();
145        int     base = 10;
146
147        if ('0' == value.charAt(index)) {
148            //  Quick check for zero by itself
149            if (index == (len - 1))
150                return 0;
151
152            char    c = value.charAt(index + 1);
153
154            if ('x' == c || 'X' == c) {     //  check for hex
155                index += 2;
156                base = 16;
157            } else {                        //  check for octal
158                index++;
159                base = 8;
160            }
161        } else if ('#' == value.charAt(index)) {
162            index++;
163            base = 16;
164        }
165
166        return (int) Long.parseLong(value.substring(index), base);
167    }
168
169    /**
170     * Flatten a Map into an output stream as XML.  The map can later be
171     * read back with readMapXml().
172     *
173     * @param val The map to be flattened.
174     * @param out Where to write the XML data.
175     *
176     * @see #writeMapXml(Map, String, XmlSerializer)
177     * @see #writeListXml
178     * @see #writeValueXml
179     * @see #readMapXml
180     */
181    public static final void writeMapXml(Map val, OutputStream out)
182            throws XmlPullParserException, java.io.IOException {
183        XmlSerializer serializer = new FastXmlSerializer();
184        serializer.setOutput(out, "utf-8");
185        serializer.startDocument(null, true);
186        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
187        writeMapXml(val, null, serializer);
188        serializer.endDocument();
189    }
190
191    /**
192     * Flatten a List into an output stream as XML.  The list can later be
193     * read back with readListXml().
194     *
195     * @param val The list to be flattened.
196     * @param out Where to write the XML data.
197     *
198     * @see #writeListXml(List, String, XmlSerializer)
199     * @see #writeMapXml
200     * @see #writeValueXml
201     * @see #readListXml
202     */
203    public static final void writeListXml(List val, OutputStream out)
204    throws XmlPullParserException, java.io.IOException
205    {
206        XmlSerializer serializer = Xml.newSerializer();
207        serializer.setOutput(out, "utf-8");
208        serializer.startDocument(null, true);
209        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
210        writeListXml(val, null, serializer);
211        serializer.endDocument();
212    }
213
214    /**
215     * Flatten a Map into an XmlSerializer.  The map can later be read back
216     * with readThisMapXml().
217     *
218     * @param val The map to be flattened.
219     * @param name Name attribute to include with this list's tag, or null for
220     *             none.
221     * @param out XmlSerializer to write the map into.
222     *
223     * @see #writeMapXml(Map, OutputStream)
224     * @see #writeListXml
225     * @see #writeValueXml
226     * @see #readMapXml
227     */
228    public static final void writeMapXml(Map val, String name, XmlSerializer out)
229            throws XmlPullParserException, java.io.IOException {
230        writeMapXml(val, name, out, null);
231    }
232
233    /**
234     * Flatten a Map into an XmlSerializer.  The map can later be read back
235     * with readThisMapXml().
236     *
237     * @param val The map to be flattened.
238     * @param name Name attribute to include with this list's tag, or null for
239     *             none.
240     * @param out XmlSerializer to write the map into.
241     * @param callback Method to call when an Object type is not recognized.
242     *
243     * @see #writeMapXml(Map, OutputStream)
244     * @see #writeListXml
245     * @see #writeValueXml
246     * @see #readMapXml
247     *
248     * @hide
249     */
250    public static final void writeMapXml(Map val, String name, XmlSerializer out,
251            WriteMapCallback callback) throws XmlPullParserException, java.io.IOException {
252
253        if (val == null) {
254            out.startTag(null, "null");
255            out.endTag(null, "null");
256            return;
257        }
258
259        out.startTag(null, "map");
260        if (name != null) {
261            out.attribute(null, "name", name);
262        }
263
264        writeMapXml(val, out, callback);
265
266        out.endTag(null, "map");
267    }
268
269    /**
270     * Flatten a Map into an XmlSerializer.  The map can later be read back
271     * with readThisMapXml(). This method presumes that the start tag and
272     * name attribute have already been written and does not write an end tag.
273     *
274     * @param val The map to be flattened.
275     * @param out XmlSerializer to write the map into.
276     *
277     * @see #writeMapXml(Map, OutputStream)
278     * @see #writeListXml
279     * @see #writeValueXml
280     * @see #readMapXml
281     *
282     * @hide
283     */
284    public static final void writeMapXml(Map val, XmlSerializer out,
285            WriteMapCallback callback) throws XmlPullParserException, java.io.IOException {
286        if (val == null) {
287            return;
288        }
289
290        Set s = val.entrySet();
291        Iterator i = s.iterator();
292
293        while (i.hasNext()) {
294            Map.Entry e = (Map.Entry)i.next();
295            writeValueXml(e.getValue(), (String)e.getKey(), out, callback);
296        }
297    }
298
299    /**
300     * Flatten a List into an XmlSerializer.  The list can later be read back
301     * with readThisListXml().
302     *
303     * @param val The list to be flattened.
304     * @param name Name attribute to include with this list's tag, or null for
305     *             none.
306     * @param out XmlSerializer to write the list into.
307     *
308     * @see #writeListXml(List, OutputStream)
309     * @see #writeMapXml
310     * @see #writeValueXml
311     * @see #readListXml
312     */
313    public static final void writeListXml(List val, String name, XmlSerializer out)
314    throws XmlPullParserException, java.io.IOException
315    {
316        if (val == null) {
317            out.startTag(null, "null");
318            out.endTag(null, "null");
319            return;
320        }
321
322        out.startTag(null, "list");
323        if (name != null) {
324            out.attribute(null, "name", name);
325        }
326
327        int N = val.size();
328        int i=0;
329        while (i < N) {
330            writeValueXml(val.get(i), null, out);
331            i++;
332        }
333
334        out.endTag(null, "list");
335    }
336
337    public static final void writeSetXml(Set val, String name, XmlSerializer out)
338            throws XmlPullParserException, java.io.IOException {
339        if (val == null) {
340            out.startTag(null, "null");
341            out.endTag(null, "null");
342            return;
343        }
344
345        out.startTag(null, "set");
346        if (name != null) {
347            out.attribute(null, "name", name);
348        }
349
350        for (Object v : val) {
351            writeValueXml(v, null, out);
352        }
353
354        out.endTag(null, "set");
355    }
356
357    /**
358     * Flatten a byte[] into an XmlSerializer.  The list can later be read back
359     * with readThisByteArrayXml().
360     *
361     * @param val The byte array to be flattened.
362     * @param name Name attribute to include with this array's tag, or null for
363     *             none.
364     * @param out XmlSerializer to write the array into.
365     *
366     * @see #writeMapXml
367     * @see #writeValueXml
368     */
369    public static final void writeByteArrayXml(byte[] val, String name,
370            XmlSerializer out)
371            throws XmlPullParserException, java.io.IOException {
372
373        if (val == null) {
374            out.startTag(null, "null");
375            out.endTag(null, "null");
376            return;
377        }
378
379        out.startTag(null, "byte-array");
380        if (name != null) {
381            out.attribute(null, "name", name);
382        }
383
384        final int N = val.length;
385        out.attribute(null, "num", Integer.toString(N));
386
387        StringBuilder sb = new StringBuilder(val.length*2);
388        for (int i=0; i<N; i++) {
389            int b = val[i];
390            int h = b>>4;
391            sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
392            h = b&0xff;
393            sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
394        }
395
396        out.text(sb.toString());
397
398        out.endTag(null, "byte-array");
399    }
400
401    /**
402     * Flatten an int[] into an XmlSerializer.  The list can later be read back
403     * with readThisIntArrayXml().
404     *
405     * @param val The int array to be flattened.
406     * @param name Name attribute to include with this array's tag, or null for
407     *             none.
408     * @param out XmlSerializer to write the array into.
409     *
410     * @see #writeMapXml
411     * @see #writeValueXml
412     * @see #readThisIntArrayXml
413     */
414    public static final void writeIntArrayXml(int[] val, String name,
415            XmlSerializer out)
416            throws XmlPullParserException, java.io.IOException {
417
418        if (val == null) {
419            out.startTag(null, "null");
420            out.endTag(null, "null");
421            return;
422        }
423
424        out.startTag(null, "int-array");
425        if (name != null) {
426            out.attribute(null, "name", name);
427        }
428
429        final int N = val.length;
430        out.attribute(null, "num", Integer.toString(N));
431
432        for (int i=0; i<N; i++) {
433            out.startTag(null, "item");
434            out.attribute(null, "value", Integer.toString(val[i]));
435            out.endTag(null, "item");
436        }
437
438        out.endTag(null, "int-array");
439    }
440
441    /**
442     * Flatten a long[] into an XmlSerializer.  The list can later be read back
443     * with readThisLongArrayXml().
444     *
445     * @param val The long array to be flattened.
446     * @param name Name attribute to include with this array's tag, or null for
447     *             none.
448     * @param out XmlSerializer to write the array into.
449     *
450     * @see #writeMapXml
451     * @see #writeValueXml
452     * @see #readThisIntArrayXml
453     */
454    public static final void writeLongArrayXml(long[] val, String name, XmlSerializer out)
455            throws XmlPullParserException, java.io.IOException {
456
457        if (val == null) {
458            out.startTag(null, "null");
459            out.endTag(null, "null");
460            return;
461        }
462
463        out.startTag(null, "long-array");
464        if (name != null) {
465            out.attribute(null, "name", name);
466        }
467
468        final int N = val.length;
469        out.attribute(null, "num", Integer.toString(N));
470
471        for (int i=0; i<N; i++) {
472            out.startTag(null, "item");
473            out.attribute(null, "value", Long.toString(val[i]));
474            out.endTag(null, "item");
475        }
476
477        out.endTag(null, "long-array");
478    }
479
480    /**
481     * Flatten a double[] into an XmlSerializer.  The list can later be read back
482     * with readThisDoubleArrayXml().
483     *
484     * @param val The double array to be flattened.
485     * @param name Name attribute to include with this array's tag, or null for
486     *             none.
487     * @param out XmlSerializer to write the array into.
488     *
489     * @see #writeMapXml
490     * @see #writeValueXml
491     * @see #readThisIntArrayXml
492     */
493    public static final void writeDoubleArrayXml(double[] val, String name, XmlSerializer out)
494            throws XmlPullParserException, java.io.IOException {
495
496        if (val == null) {
497            out.startTag(null, "null");
498            out.endTag(null, "null");
499            return;
500        }
501
502        out.startTag(null, "double-array");
503        if (name != null) {
504            out.attribute(null, "name", name);
505        }
506
507        final int N = val.length;
508        out.attribute(null, "num", Integer.toString(N));
509
510        for (int i=0; i<N; i++) {
511            out.startTag(null, "item");
512            out.attribute(null, "value", Double.toString(val[i]));
513            out.endTag(null, "item");
514        }
515
516        out.endTag(null, "double-array");
517    }
518
519    /**
520     * Flatten a String[] into an XmlSerializer.  The list can later be read back
521     * with readThisStringArrayXml().
522     *
523     * @param val The String array to be flattened.
524     * @param name Name attribute to include with this array's tag, or null for
525     *             none.
526     * @param out XmlSerializer to write the array into.
527     *
528     * @see #writeMapXml
529     * @see #writeValueXml
530     * @see #readThisIntArrayXml
531     */
532    public static final void writeStringArrayXml(String[] val, String name, XmlSerializer out)
533            throws XmlPullParserException, java.io.IOException {
534
535        if (val == null) {
536            out.startTag(null, "null");
537            out.endTag(null, "null");
538            return;
539        }
540
541        out.startTag(null, "string-array");
542        if (name != null) {
543            out.attribute(null, "name", name);
544        }
545
546        final int N = val.length;
547        out.attribute(null, "num", Integer.toString(N));
548
549        for (int i=0; i<N; i++) {
550            out.startTag(null, "item");
551            out.attribute(null, "value", val[i]);
552            out.endTag(null, "item");
553        }
554
555        out.endTag(null, "string-array");
556    }
557
558    /**
559     * Flatten a boolean[] into an XmlSerializer.  The list can later be read back
560     * with readThisBooleanArrayXml().
561     *
562     * @param val The boolean array to be flattened.
563     * @param name Name attribute to include with this array's tag, or null for
564     *             none.
565     * @param out XmlSerializer to write the array into.
566     *
567     * @see #writeMapXml
568     * @see #writeValueXml
569     * @see #readThisIntArrayXml
570     */
571    public static final void writeBooleanArrayXml(boolean[] val, String name, XmlSerializer out)
572            throws XmlPullParserException, java.io.IOException {
573
574        if (val == null) {
575            out.startTag(null, "null");
576            out.endTag(null, "null");
577            return;
578        }
579
580        out.startTag(null, "boolean-array");
581        if (name != null) {
582            out.attribute(null, "name", name);
583        }
584
585        final int N = val.length;
586        out.attribute(null, "num", Integer.toString(N));
587
588        for (int i=0; i<N; i++) {
589            out.startTag(null, "item");
590            out.attribute(null, "value", Boolean.toString(val[i]));
591            out.endTag(null, "item");
592        }
593
594        out.endTag(null, "boolean-array");
595    }
596
597    /**
598     * Flatten an object's value into an XmlSerializer.  The value can later
599     * be read back with readThisValueXml().
600     *
601     * Currently supported value types are: null, String, Integer, Long,
602     * Float, Double Boolean, Map, List.
603     *
604     * @param v The object to be flattened.
605     * @param name Name attribute to include with this value's tag, or null
606     *             for none.
607     * @param out XmlSerializer to write the object into.
608     *
609     * @see #writeMapXml
610     * @see #writeListXml
611     * @see #readValueXml
612     */
613    public static final void writeValueXml(Object v, String name, XmlSerializer out)
614            throws XmlPullParserException, java.io.IOException {
615        writeValueXml(v, name, out, null);
616    }
617
618    /**
619     * Flatten an object's value into an XmlSerializer.  The value can later
620     * be read back with readThisValueXml().
621     *
622     * Currently supported value types are: null, String, Integer, Long,
623     * Float, Double Boolean, Map, List.
624     *
625     * @param v The object to be flattened.
626     * @param name Name attribute to include with this value's tag, or null
627     *             for none.
628     * @param out XmlSerializer to write the object into.
629     * @param callback Handler for Object types not recognized.
630     *
631     * @see #writeMapXml
632     * @see #writeListXml
633     * @see #readValueXml
634     */
635    private static final void writeValueXml(Object v, String name, XmlSerializer out,
636            WriteMapCallback callback)  throws XmlPullParserException, java.io.IOException {
637        String typeStr;
638        if (v == null) {
639            out.startTag(null, "null");
640            if (name != null) {
641                out.attribute(null, "name", name);
642            }
643            out.endTag(null, "null");
644            return;
645        } else if (v instanceof String) {
646            out.startTag(null, "string");
647            if (name != null) {
648                out.attribute(null, "name", name);
649            }
650            out.text(v.toString());
651            out.endTag(null, "string");
652            return;
653        } else if (v instanceof Integer) {
654            typeStr = "int";
655        } else if (v instanceof Long) {
656            typeStr = "long";
657        } else if (v instanceof Float) {
658            typeStr = "float";
659        } else if (v instanceof Double) {
660            typeStr = "double";
661        } else if (v instanceof Boolean) {
662            typeStr = "boolean";
663        } else if (v instanceof byte[]) {
664            writeByteArrayXml((byte[])v, name, out);
665            return;
666        } else if (v instanceof int[]) {
667            writeIntArrayXml((int[])v, name, out);
668            return;
669        } else if (v instanceof long[]) {
670            writeLongArrayXml((long[])v, name, out);
671            return;
672        } else if (v instanceof double[]) {
673            writeDoubleArrayXml((double[])v, name, out);
674            return;
675        } else if (v instanceof String[]) {
676            writeStringArrayXml((String[])v, name, out);
677            return;
678        } else if (v instanceof boolean[]) {
679            writeBooleanArrayXml((boolean[])v, name, out);
680            return;
681        } else if (v instanceof Map) {
682            writeMapXml((Map)v, name, out);
683            return;
684        } else if (v instanceof List) {
685            writeListXml((List) v, name, out);
686            return;
687        } else if (v instanceof Set) {
688            writeSetXml((Set) v, name, out);
689            return;
690        } else if (v instanceof CharSequence) {
691            // XXX This is to allow us to at least write something if
692            // we encounter styled text...  but it means we will drop all
693            // of the styling information. :(
694            out.startTag(null, "string");
695            if (name != null) {
696                out.attribute(null, "name", name);
697            }
698            out.text(v.toString());
699            out.endTag(null, "string");
700            return;
701        } else if (callback != null) {
702            callback.writeUnknownObject(v, name, out);
703            return;
704        } else {
705            throw new RuntimeException("writeValueXml: unable to write value " + v);
706        }
707
708        out.startTag(null, typeStr);
709        if (name != null) {
710            out.attribute(null, "name", name);
711        }
712        out.attribute(null, "value", v.toString());
713        out.endTag(null, typeStr);
714    }
715
716    /**
717     * Read a HashMap from an InputStream containing XML.  The stream can
718     * previously have been written by writeMapXml().
719     *
720     * @param in The InputStream from which to read.
721     *
722     * @return HashMap The resulting map.
723     *
724     * @see #readListXml
725     * @see #readValueXml
726     * @see #readThisMapXml
727     * #see #writeMapXml
728     */
729    @SuppressWarnings("unchecked")
730    public static final HashMap<String, ?> readMapXml(InputStream in)
731    throws XmlPullParserException, java.io.IOException
732    {
733        XmlPullParser   parser = Xml.newPullParser();
734        parser.setInput(in, null);
735        return (HashMap<String, ?>) readValueXml(parser, new String[1]);
736    }
737
738    /**
739     * Read an ArrayList from an InputStream containing XML.  The stream can
740     * previously have been written by writeListXml().
741     *
742     * @param in The InputStream from which to read.
743     *
744     * @return ArrayList The resulting list.
745     *
746     * @see #readMapXml
747     * @see #readValueXml
748     * @see #readThisListXml
749     * @see #writeListXml
750     */
751    public static final ArrayList readListXml(InputStream in)
752    throws XmlPullParserException, java.io.IOException
753    {
754        XmlPullParser   parser = Xml.newPullParser();
755        parser.setInput(in, null);
756        return (ArrayList)readValueXml(parser, new String[1]);
757    }
758
759
760    /**
761     * Read a HashSet from an InputStream containing XML. The stream can
762     * previously have been written by writeSetXml().
763     *
764     * @param in The InputStream from which to read.
765     *
766     * @return HashSet The resulting set.
767     *
768     * @throws XmlPullParserException
769     * @throws java.io.IOException
770     *
771     * @see #readValueXml
772     * @see #readThisSetXml
773     * @see #writeSetXml
774     */
775    public static final HashSet readSetXml(InputStream in)
776            throws XmlPullParserException, java.io.IOException {
777        XmlPullParser parser = Xml.newPullParser();
778        parser.setInput(in, null);
779        return (HashSet) readValueXml(parser, new String[1]);
780    }
781
782    /**
783     * Read a HashMap object from an XmlPullParser.  The XML data could
784     * previously have been generated by writeMapXml().  The XmlPullParser
785     * must be positioned <em>after</em> the tag that begins the map.
786     *
787     * @param parser The XmlPullParser from which to read the map data.
788     * @param endTag Name of the tag that will end the map, usually "map".
789     * @param name An array of one string, used to return the name attribute
790     *             of the map's tag.
791     *
792     * @return HashMap The newly generated map.
793     *
794     * @see #readMapXml
795     */
796    public static final HashMap<String, ?> readThisMapXml(XmlPullParser parser, String endTag,
797            String[] name) throws XmlPullParserException, java.io.IOException {
798        return readThisMapXml(parser, endTag, name, null);
799    }
800
801    /**
802     * Read a HashMap object from an XmlPullParser.  The XML data could
803     * previously have been generated by writeMapXml().  The XmlPullParser
804     * must be positioned <em>after</em> the tag that begins the map.
805     *
806     * @param parser The XmlPullParser from which to read the map data.
807     * @param endTag Name of the tag that will end the map, usually "map".
808     * @param name An array of one string, used to return the name attribute
809     *             of the map's tag.
810     *
811     * @return HashMap The newly generated map.
812     *
813     * @see #readMapXml
814     * @hide
815     */
816    public static final HashMap<String, ?> readThisMapXml(XmlPullParser parser, String endTag,
817            String[] name, ReadMapCallback callback)
818            throws XmlPullParserException, java.io.IOException
819    {
820        HashMap<String, Object> map = new HashMap<String, Object>();
821
822        int eventType = parser.getEventType();
823        do {
824            if (eventType == parser.START_TAG) {
825                Object val = readThisValueXml(parser, name, callback);
826                map.put(name[0], val);
827            } else if (eventType == parser.END_TAG) {
828                if (parser.getName().equals(endTag)) {
829                    return map;
830                }
831                throw new XmlPullParserException(
832                    "Expected " + endTag + " end tag at: " + parser.getName());
833            }
834            eventType = parser.next();
835        } while (eventType != parser.END_DOCUMENT);
836
837        throw new XmlPullParserException(
838            "Document ended before " + endTag + " end tag");
839    }
840
841    /**
842     * Read an ArrayList object from an XmlPullParser.  The XML data could
843     * previously have been generated by writeListXml().  The XmlPullParser
844     * must be positioned <em>after</em> the tag that begins the list.
845     *
846     * @param parser The XmlPullParser from which to read the list data.
847     * @param endTag Name of the tag that will end the list, usually "list".
848     * @param name An array of one string, used to return the name attribute
849     *             of the list's tag.
850     *
851     * @return HashMap The newly generated list.
852     *
853     * @see #readListXml
854     */
855    public static final ArrayList readThisListXml(XmlPullParser parser, String endTag,
856            String[] name) throws XmlPullParserException, java.io.IOException {
857        return readThisListXml(parser, endTag, name, null);
858    }
859
860    /**
861     * Read an ArrayList object from an XmlPullParser.  The XML data could
862     * previously have been generated by writeListXml().  The XmlPullParser
863     * must be positioned <em>after</em> the tag that begins the list.
864     *
865     * @param parser The XmlPullParser from which to read the list data.
866     * @param endTag Name of the tag that will end the list, usually "list".
867     * @param name An array of one string, used to return the name attribute
868     *             of the list's tag.
869     *
870     * @return HashMap The newly generated list.
871     *
872     * @see #readListXml
873     */
874    private static final ArrayList readThisListXml(XmlPullParser parser, String endTag,
875            String[] name, ReadMapCallback callback)
876            throws XmlPullParserException, java.io.IOException {
877        ArrayList list = new ArrayList();
878
879        int eventType = parser.getEventType();
880        do {
881            if (eventType == parser.START_TAG) {
882                Object val = readThisValueXml(parser, name, callback);
883                list.add(val);
884                //System.out.println("Adding to list: " + val);
885            } else if (eventType == parser.END_TAG) {
886                if (parser.getName().equals(endTag)) {
887                    return list;
888                }
889                throw new XmlPullParserException(
890                    "Expected " + endTag + " end tag at: " + parser.getName());
891            }
892            eventType = parser.next();
893        } while (eventType != parser.END_DOCUMENT);
894
895        throw new XmlPullParserException(
896            "Document ended before " + endTag + " end tag");
897    }
898
899    /**
900     * Read a HashSet object from an XmlPullParser. The XML data could previously
901     * have been generated by writeSetXml(). The XmlPullParser must be positioned
902     * <em>after</em> the tag that begins the set.
903     *
904     * @param parser The XmlPullParser from which to read the set data.
905     * @param endTag Name of the tag that will end the set, usually "set".
906     * @param name An array of one string, used to return the name attribute
907     *             of the set's tag.
908     *
909     * @return HashSet The newly generated set.
910     *
911     * @throws XmlPullParserException
912     * @throws java.io.IOException
913     *
914     * @see #readSetXml
915     */
916    public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name)
917            throws XmlPullParserException, java.io.IOException {
918        return readThisSetXml(parser, endTag, name, null);
919    }
920
921    /**
922     * Read a HashSet object from an XmlPullParser. The XML data could previously
923     * have been generated by writeSetXml(). The XmlPullParser must be positioned
924     * <em>after</em> the tag that begins the set.
925     *
926     * @param parser The XmlPullParser from which to read the set data.
927     * @param endTag Name of the tag that will end the set, usually "set".
928     * @param name An array of one string, used to return the name attribute
929     *             of the set's tag.
930     *
931     * @return HashSet The newly generated set.
932     *
933     * @throws XmlPullParserException
934     * @throws java.io.IOException
935     *
936     * @see #readSetXml
937     * @hide
938     */
939    private static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name,
940            ReadMapCallback callback) throws XmlPullParserException, java.io.IOException {
941        HashSet set = new HashSet();
942
943        int eventType = parser.getEventType();
944        do {
945            if (eventType == parser.START_TAG) {
946                Object val = readThisValueXml(parser, name, callback);
947                set.add(val);
948                //System.out.println("Adding to set: " + val);
949            } else if (eventType == parser.END_TAG) {
950                if (parser.getName().equals(endTag)) {
951                    return set;
952                }
953                throw new XmlPullParserException(
954                        "Expected " + endTag + " end tag at: " + parser.getName());
955            }
956            eventType = parser.next();
957        } while (eventType != parser.END_DOCUMENT);
958
959        throw new XmlPullParserException(
960                "Document ended before " + endTag + " end tag");
961    }
962
963    /**
964     * Read an int[] object from an XmlPullParser.  The XML data could
965     * previously have been generated by writeIntArrayXml().  The XmlPullParser
966     * must be positioned <em>after</em> the tag that begins the list.
967     *
968     * @param parser The XmlPullParser from which to read the list data.
969     * @param endTag Name of the tag that will end the list, usually "list".
970     * @param name An array of one string, used to return the name attribute
971     *             of the list's tag.
972     *
973     * @return Returns a newly generated int[].
974     *
975     * @see #readListXml
976     */
977    public static final int[] readThisIntArrayXml(XmlPullParser parser,
978            String endTag, String[] name)
979            throws XmlPullParserException, java.io.IOException {
980
981        int num;
982        try {
983            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
984        } catch (NullPointerException e) {
985            throw new XmlPullParserException(
986                    "Need num attribute in byte-array");
987        } catch (NumberFormatException e) {
988            throw new XmlPullParserException(
989                    "Not a number in num attribute in byte-array");
990        }
991        parser.next();
992
993        int[] array = new int[num];
994        int i = 0;
995
996        int eventType = parser.getEventType();
997        do {
998            if (eventType == parser.START_TAG) {
999                if (parser.getName().equals("item")) {
1000                    try {
1001                        array[i] = Integer.parseInt(
1002                                parser.getAttributeValue(null, "value"));
1003                    } catch (NullPointerException e) {
1004                        throw new XmlPullParserException(
1005                                "Need value attribute in item");
1006                    } catch (NumberFormatException e) {
1007                        throw new XmlPullParserException(
1008                                "Not a number in value attribute in item");
1009                    }
1010                } else {
1011                    throw new XmlPullParserException(
1012                            "Expected item tag at: " + parser.getName());
1013                }
1014            } else if (eventType == parser.END_TAG) {
1015                if (parser.getName().equals(endTag)) {
1016                    return array;
1017                } else if (parser.getName().equals("item")) {
1018                    i++;
1019                } else {
1020                    throw new XmlPullParserException(
1021                        "Expected " + endTag + " end tag at: "
1022                        + parser.getName());
1023                }
1024            }
1025            eventType = parser.next();
1026        } while (eventType != parser.END_DOCUMENT);
1027
1028        throw new XmlPullParserException(
1029            "Document ended before " + endTag + " end tag");
1030    }
1031
1032    /**
1033     * Read a long[] object from an XmlPullParser.  The XML data could
1034     * previously have been generated by writeLongArrayXml().  The XmlPullParser
1035     * must be positioned <em>after</em> the tag that begins the list.
1036     *
1037     * @param parser The XmlPullParser from which to read the list data.
1038     * @param endTag Name of the tag that will end the list, usually "list".
1039     * @param name An array of one string, used to return the name attribute
1040     *             of the list's tag.
1041     *
1042     * @return Returns a newly generated long[].
1043     *
1044     * @see #readListXml
1045     */
1046    public static final long[] readThisLongArrayXml(XmlPullParser parser,
1047            String endTag, String[] name)
1048            throws XmlPullParserException, java.io.IOException {
1049
1050        int num;
1051        try {
1052            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
1053        } catch (NullPointerException e) {
1054            throw new XmlPullParserException("Need num attribute in long-array");
1055        } catch (NumberFormatException e) {
1056            throw new XmlPullParserException("Not a number in num attribute in long-array");
1057        }
1058        parser.next();
1059
1060        long[] array = new long[num];
1061        int i = 0;
1062
1063        int eventType = parser.getEventType();
1064        do {
1065            if (eventType == parser.START_TAG) {
1066                if (parser.getName().equals("item")) {
1067                    try {
1068                        array[i] = Long.parseLong(parser.getAttributeValue(null, "value"));
1069                    } catch (NullPointerException e) {
1070                        throw new XmlPullParserException("Need value attribute in item");
1071                    } catch (NumberFormatException e) {
1072                        throw new XmlPullParserException("Not a number in value attribute in item");
1073                    }
1074                } else {
1075                    throw new XmlPullParserException("Expected item tag at: " + parser.getName());
1076                }
1077            } else if (eventType == parser.END_TAG) {
1078                if (parser.getName().equals(endTag)) {
1079                    return array;
1080                } else if (parser.getName().equals("item")) {
1081                    i++;
1082                } else {
1083                    throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
1084                            parser.getName());
1085                }
1086            }
1087            eventType = parser.next();
1088        } while (eventType != parser.END_DOCUMENT);
1089
1090        throw new XmlPullParserException("Document ended before " + endTag + " end tag");
1091    }
1092
1093    /**
1094     * Read a double[] object from an XmlPullParser.  The XML data could
1095     * previously have been generated by writeDoubleArrayXml().  The XmlPullParser
1096     * must be positioned <em>after</em> the tag that begins the list.
1097     *
1098     * @param parser The XmlPullParser from which to read the list data.
1099     * @param endTag Name of the tag that will end the list, usually "double-array".
1100     * @param name An array of one string, used to return the name attribute
1101     *             of the list's tag.
1102     *
1103     * @return Returns a newly generated double[].
1104     *
1105     * @see #readListXml
1106     */
1107    public static final double[] readThisDoubleArrayXml(XmlPullParser parser, String endTag,
1108            String[] name) throws XmlPullParserException, java.io.IOException {
1109
1110        int num;
1111        try {
1112            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
1113        } catch (NullPointerException e) {
1114            throw new XmlPullParserException("Need num attribute in double-array");
1115        } catch (NumberFormatException e) {
1116            throw new XmlPullParserException("Not a number in num attribute in double-array");
1117        }
1118        parser.next();
1119
1120        double[] array = new double[num];
1121        int i = 0;
1122
1123        int eventType = parser.getEventType();
1124        do {
1125            if (eventType == parser.START_TAG) {
1126                if (parser.getName().equals("item")) {
1127                    try {
1128                        array[i] = Double.parseDouble(parser.getAttributeValue(null, "value"));
1129                    } catch (NullPointerException e) {
1130                        throw new XmlPullParserException("Need value attribute in item");
1131                    } catch (NumberFormatException e) {
1132                        throw new XmlPullParserException("Not a number in value attribute in item");
1133                    }
1134                } else {
1135                    throw new XmlPullParserException("Expected item tag at: " + parser.getName());
1136                }
1137            } else if (eventType == parser.END_TAG) {
1138                if (parser.getName().equals(endTag)) {
1139                    return array;
1140                } else if (parser.getName().equals("item")) {
1141                    i++;
1142                } else {
1143                    throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
1144                            parser.getName());
1145                }
1146            }
1147            eventType = parser.next();
1148        } while (eventType != parser.END_DOCUMENT);
1149
1150        throw new XmlPullParserException("Document ended before " + endTag + " end tag");
1151    }
1152
1153    /**
1154     * Read a String[] object from an XmlPullParser.  The XML data could
1155     * previously have been generated by writeStringArrayXml().  The XmlPullParser
1156     * must be positioned <em>after</em> the tag that begins the list.
1157     *
1158     * @param parser The XmlPullParser from which to read the list data.
1159     * @param endTag Name of the tag that will end the list, usually "string-array".
1160     * @param name An array of one string, used to return the name attribute
1161     *             of the list's tag.
1162     *
1163     * @return Returns a newly generated String[].
1164     *
1165     * @see #readListXml
1166     */
1167    public static final String[] readThisStringArrayXml(XmlPullParser parser, String endTag,
1168            String[] name) throws XmlPullParserException, java.io.IOException {
1169
1170        int num;
1171        try {
1172            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
1173        } catch (NullPointerException e) {
1174            throw new XmlPullParserException("Need num attribute in string-array");
1175        } catch (NumberFormatException e) {
1176            throw new XmlPullParserException("Not a number in num attribute in string-array");
1177        }
1178        parser.next();
1179
1180        String[] array = new String[num];
1181        int i = 0;
1182
1183        int eventType = parser.getEventType();
1184        do {
1185            if (eventType == parser.START_TAG) {
1186                if (parser.getName().equals("item")) {
1187                    try {
1188                        array[i] = parser.getAttributeValue(null, "value");
1189                    } catch (NullPointerException e) {
1190                        throw new XmlPullParserException("Need value attribute in item");
1191                    } catch (NumberFormatException e) {
1192                        throw new XmlPullParserException("Not a number in value attribute in item");
1193                    }
1194                } else {
1195                    throw new XmlPullParserException("Expected item tag at: " + parser.getName());
1196                }
1197            } else if (eventType == parser.END_TAG) {
1198                if (parser.getName().equals(endTag)) {
1199                    return array;
1200                } else if (parser.getName().equals("item")) {
1201                    i++;
1202                } else {
1203                    throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
1204                            parser.getName());
1205                }
1206            }
1207            eventType = parser.next();
1208        } while (eventType != parser.END_DOCUMENT);
1209
1210        throw new XmlPullParserException("Document ended before " + endTag + " end tag");
1211    }
1212
1213    /**
1214     * Read a boolean[] object from an XmlPullParser.  The XML data could
1215     * previously have been generated by writeBooleanArrayXml().  The XmlPullParser
1216     * must be positioned <em>after</em> the tag that begins the list.
1217     *
1218     * @param parser The XmlPullParser from which to read the list data.
1219     * @param endTag Name of the tag that will end the list, usually "string-array".
1220     * @param name An array of one string, used to return the name attribute
1221     *             of the list's tag.
1222     *
1223     * @return Returns a newly generated boolean[].
1224     *
1225     * @see #readListXml
1226     */
1227    public static final boolean[] readThisBooleanArrayXml(XmlPullParser parser, String endTag,
1228            String[] name) throws XmlPullParserException, java.io.IOException {
1229
1230        int num;
1231        try {
1232            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
1233        } catch (NullPointerException e) {
1234            throw new XmlPullParserException("Need num attribute in string-array");
1235        } catch (NumberFormatException e) {
1236            throw new XmlPullParserException("Not a number in num attribute in string-array");
1237        }
1238        parser.next();
1239
1240        boolean[] array = new boolean[num];
1241        int i = 0;
1242
1243        int eventType = parser.getEventType();
1244        do {
1245            if (eventType == parser.START_TAG) {
1246                if (parser.getName().equals("item")) {
1247                    try {
1248                        array[i] = Boolean.valueOf(parser.getAttributeValue(null, "value"));
1249                    } catch (NullPointerException e) {
1250                        throw new XmlPullParserException("Need value attribute in item");
1251                    } catch (NumberFormatException e) {
1252                        throw new XmlPullParserException("Not a number in value attribute in item");
1253                    }
1254                } else {
1255                    throw new XmlPullParserException("Expected item tag at: " + parser.getName());
1256                }
1257            } else if (eventType == parser.END_TAG) {
1258                if (parser.getName().equals(endTag)) {
1259                    return array;
1260                } else if (parser.getName().equals("item")) {
1261                    i++;
1262                } else {
1263                    throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
1264                            parser.getName());
1265                }
1266            }
1267            eventType = parser.next();
1268        } while (eventType != parser.END_DOCUMENT);
1269
1270        throw new XmlPullParserException("Document ended before " + endTag + " end tag");
1271    }
1272
1273    /**
1274     * Read a flattened object from an XmlPullParser.  The XML data could
1275     * previously have been written with writeMapXml(), writeListXml(), or
1276     * writeValueXml().  The XmlPullParser must be positioned <em>at</em> the
1277     * tag that defines the value.
1278     *
1279     * @param parser The XmlPullParser from which to read the object.
1280     * @param name An array of one string, used to return the name attribute
1281     *             of the value's tag.
1282     *
1283     * @return Object The newly generated value object.
1284     *
1285     * @see #readMapXml
1286     * @see #readListXml
1287     * @see #writeValueXml
1288     */
1289    public static final Object readValueXml(XmlPullParser parser, String[] name)
1290    throws XmlPullParserException, java.io.IOException
1291    {
1292        int eventType = parser.getEventType();
1293        do {
1294            if (eventType == parser.START_TAG) {
1295                return readThisValueXml(parser, name, null);
1296            } else if (eventType == parser.END_TAG) {
1297                throw new XmlPullParserException(
1298                    "Unexpected end tag at: " + parser.getName());
1299            } else if (eventType == parser.TEXT) {
1300                throw new XmlPullParserException(
1301                    "Unexpected text: " + parser.getText());
1302            }
1303            eventType = parser.next();
1304        } while (eventType != parser.END_DOCUMENT);
1305
1306        throw new XmlPullParserException(
1307            "Unexpected end of document");
1308    }
1309
1310    private static final Object readThisValueXml(XmlPullParser parser, String[] name,
1311            ReadMapCallback callback)  throws XmlPullParserException, java.io.IOException {
1312        final String valueName = parser.getAttributeValue(null, "name");
1313        final String tagName = parser.getName();
1314
1315        //System.out.println("Reading this value tag: " + tagName + ", name=" + valueName);
1316
1317        Object res;
1318
1319        if (tagName.equals("null")) {
1320            res = null;
1321        } else if (tagName.equals("string")) {
1322            String value = "";
1323            int eventType;
1324            while ((eventType = parser.next()) != parser.END_DOCUMENT) {
1325                if (eventType == parser.END_TAG) {
1326                    if (parser.getName().equals("string")) {
1327                        name[0] = valueName;
1328                        //System.out.println("Returning value for " + valueName + ": " + value);
1329                        return value;
1330                    }
1331                    throw new XmlPullParserException(
1332                        "Unexpected end tag in <string>: " + parser.getName());
1333                } else if (eventType == parser.TEXT) {
1334                    value += parser.getText();
1335                } else if (eventType == parser.START_TAG) {
1336                    throw new XmlPullParserException(
1337                        "Unexpected start tag in <string>: " + parser.getName());
1338                }
1339            }
1340            throw new XmlPullParserException(
1341                "Unexpected end of document in <string>");
1342        } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) {
1343            // all work already done by readThisPrimitiveValueXml
1344        } else if (tagName.equals("int-array")) {
1345            res = readThisIntArrayXml(parser, "int-array", name);
1346            name[0] = valueName;
1347            //System.out.println("Returning value for " + valueName + ": " + res);
1348            return res;
1349        } else if (tagName.equals("long-array")) {
1350            res = readThisLongArrayXml(parser, "long-array", name);
1351            name[0] = valueName;
1352            //System.out.println("Returning value for " + valueName + ": " + res);
1353            return res;
1354        } else if (tagName.equals("double-array")) {
1355            res = readThisDoubleArrayXml(parser, "double-array", name);
1356            name[0] = valueName;
1357            //System.out.println("Returning value for " + valueName + ": " + res);
1358            return res;
1359        } else if (tagName.equals("string-array")) {
1360            res = readThisStringArrayXml(parser, "string-array", name);
1361            name[0] = valueName;
1362            //System.out.println("Returning value for " + valueName + ": " + res);
1363            return res;
1364        } else if (tagName.equals("boolean-array")) {
1365            res = readThisBooleanArrayXml(parser, "boolean-array", name);
1366            name[0] = valueName;
1367            //System.out.println("Returning value for " + valueName + ": " + res);
1368            return res;
1369        } else if (tagName.equals("map")) {
1370            parser.next();
1371            res = readThisMapXml(parser, "map", name);
1372            name[0] = valueName;
1373            //System.out.println("Returning value for " + valueName + ": " + res);
1374            return res;
1375        } else if (tagName.equals("list")) {
1376            parser.next();
1377            res = readThisListXml(parser, "list", name);
1378            name[0] = valueName;
1379            //System.out.println("Returning value for " + valueName + ": " + res);
1380            return res;
1381        } else if (tagName.equals("set")) {
1382            parser.next();
1383            res = readThisSetXml(parser, "set", name);
1384            name[0] = valueName;
1385            //System.out.println("Returning value for " + valueName + ": " + res);
1386            return res;
1387        } else if (callback != null) {
1388            res = callback.readThisUnknownObjectXml(parser, tagName);
1389            name[0] = valueName;
1390            return res;
1391        } else {
1392            throw new XmlPullParserException("Unknown tag: " + tagName);
1393        }
1394
1395        // Skip through to end tag.
1396        int eventType;
1397        while ((eventType = parser.next()) != parser.END_DOCUMENT) {
1398            if (eventType == parser.END_TAG) {
1399                if (parser.getName().equals(tagName)) {
1400                    name[0] = valueName;
1401                    //System.out.println("Returning value for " + valueName + ": " + res);
1402                    return res;
1403                }
1404                throw new XmlPullParserException(
1405                    "Unexpected end tag in <" + tagName + ">: " + parser.getName());
1406            } else if (eventType == parser.TEXT) {
1407                throw new XmlPullParserException(
1408                "Unexpected text in <" + tagName + ">: " + parser.getName());
1409            } else if (eventType == parser.START_TAG) {
1410                throw new XmlPullParserException(
1411                    "Unexpected start tag in <" + tagName + ">: " + parser.getName());
1412            }
1413        }
1414        throw new XmlPullParserException(
1415            "Unexpected end of document in <" + tagName + ">");
1416    }
1417
1418    private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName)
1419    throws XmlPullParserException, java.io.IOException
1420    {
1421        try {
1422            if (tagName.equals("int")) {
1423                return Integer.parseInt(parser.getAttributeValue(null, "value"));
1424            } else if (tagName.equals("long")) {
1425                return Long.valueOf(parser.getAttributeValue(null, "value"));
1426            } else if (tagName.equals("float")) {
1427                return new Float(parser.getAttributeValue(null, "value"));
1428            } else if (tagName.equals("double")) {
1429                return new Double(parser.getAttributeValue(null, "value"));
1430            } else if (tagName.equals("boolean")) {
1431                return Boolean.valueOf(parser.getAttributeValue(null, "value"));
1432            } else {
1433                return null;
1434            }
1435        } catch (NullPointerException e) {
1436            throw new XmlPullParserException("Need value attribute in <" + tagName + ">");
1437        } catch (NumberFormatException e) {
1438            throw new XmlPullParserException(
1439                    "Not a number in value attribute in <" + tagName + ">");
1440        }
1441    }
1442
1443    public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException
1444    {
1445        int type;
1446        while ((type=parser.next()) != parser.START_TAG
1447                   && type != parser.END_DOCUMENT) {
1448            ;
1449        }
1450
1451        if (type != parser.START_TAG) {
1452            throw new XmlPullParserException("No start tag found");
1453        }
1454
1455        if (!parser.getName().equals(firstElementName)) {
1456            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
1457                    ", expected " + firstElementName);
1458        }
1459    }
1460
1461    public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException
1462    {
1463        int type;
1464        while ((type=parser.next()) != parser.START_TAG
1465                   && type != parser.END_DOCUMENT) {
1466            ;
1467        }
1468    }
1469
1470    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
1471            throws IOException, XmlPullParserException {
1472        for (;;) {
1473            int type = parser.next();
1474            if (type == XmlPullParser.END_DOCUMENT
1475                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
1476                return false;
1477            }
1478            if (type == XmlPullParser.START_TAG
1479                    && parser.getDepth() == outerDepth + 1) {
1480                return true;
1481            }
1482        }
1483    }
1484
1485    public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) {
1486        final String value = in.getAttributeValue(null, name);
1487        try {
1488            return Integer.parseInt(value);
1489        } catch (NumberFormatException e) {
1490            return defaultValue;
1491        }
1492    }
1493
1494    public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
1495        final String value = in.getAttributeValue(null, name);
1496        try {
1497            return Integer.parseInt(value);
1498        } catch (NumberFormatException e) {
1499            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
1500        }
1501    }
1502
1503    public static void writeIntAttribute(XmlSerializer out, String name, int value)
1504            throws IOException {
1505        out.attribute(null, name, Integer.toString(value));
1506    }
1507
1508    public static long readLongAttribute(XmlPullParser in, String name, long defaultValue) {
1509        final String value = in.getAttributeValue(null, name);
1510        try {
1511            return Long.parseLong(value);
1512        } catch (NumberFormatException e) {
1513            return defaultValue;
1514        }
1515    }
1516
1517    public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
1518        final String value = in.getAttributeValue(null, name);
1519        try {
1520            return Long.parseLong(value);
1521        } catch (NumberFormatException e) {
1522            throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
1523        }
1524    }
1525
1526    public static void writeLongAttribute(XmlSerializer out, String name, long value)
1527            throws IOException {
1528        out.attribute(null, name, Long.toString(value));
1529    }
1530
1531    public static float readFloatAttribute(XmlPullParser in, String name) throws IOException {
1532        final String value = in.getAttributeValue(null, name);
1533        try {
1534            return Float.parseFloat(value);
1535        } catch (NumberFormatException e) {
1536            throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
1537        }
1538    }
1539
1540    public static void writeFloatAttribute(XmlSerializer out, String name, float value)
1541            throws IOException {
1542        out.attribute(null, name, Float.toString(value));
1543    }
1544
1545    public static boolean readBooleanAttribute(XmlPullParser in, String name) {
1546        final String value = in.getAttributeValue(null, name);
1547        return Boolean.parseBoolean(value);
1548    }
1549
1550    public static boolean readBooleanAttribute(XmlPullParser in, String name,
1551            boolean defaultValue) {
1552        final String value = in.getAttributeValue(null, name);
1553        if (value == null) {
1554            return defaultValue;
1555        } else {
1556            return Boolean.parseBoolean(value);
1557        }
1558    }
1559
1560    public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
1561            throws IOException {
1562        out.attribute(null, name, Boolean.toString(value));
1563    }
1564
1565    public static Uri readUriAttribute(XmlPullParser in, String name) {
1566        final String value = in.getAttributeValue(null, name);
1567        return (value != null) ? Uri.parse(value) : null;
1568    }
1569
1570    public static void writeUriAttribute(XmlSerializer out, String name, Uri value)
1571            throws IOException {
1572        if (value != null) {
1573            out.attribute(null, name, value.toString());
1574        }
1575    }
1576
1577    public static String readStringAttribute(XmlPullParser in, String name) {
1578        return in.getAttributeValue(null, name);
1579    }
1580
1581    public static void writeStringAttribute(XmlSerializer out, String name, String value)
1582            throws IOException {
1583        if (value != null) {
1584            out.attribute(null, name, value);
1585        }
1586    }
1587
1588    public static byte[] readByteArrayAttribute(XmlPullParser in, String name) {
1589        final String value = in.getAttributeValue(null, name);
1590        if (value != null) {
1591            return Base64.decode(value, Base64.DEFAULT);
1592        } else {
1593            return null;
1594        }
1595    }
1596
1597    public static void writeByteArrayAttribute(XmlSerializer out, String name, byte[] value)
1598            throws IOException {
1599        if (value != null) {
1600            out.attribute(null, name, Base64.encodeToString(value, Base64.DEFAULT));
1601        }
1602    }
1603
1604    public static Bitmap readBitmapAttribute(XmlPullParser in, String name) {
1605        final byte[] value = readByteArrayAttribute(in, name);
1606        if (value != null) {
1607            return BitmapFactory.decodeByteArray(value, 0, value.length);
1608        } else {
1609            return null;
1610        }
1611    }
1612
1613    @Deprecated
1614    public static void writeBitmapAttribute(XmlSerializer out, String name, Bitmap value)
1615            throws IOException {
1616        if (value != null) {
1617            final ByteArrayOutputStream os = new ByteArrayOutputStream();
1618            value.compress(CompressFormat.PNG, 90, os);
1619            writeByteArrayAttribute(out, name, os.toByteArray());
1620        }
1621    }
1622
1623    /** @hide */
1624    public interface WriteMapCallback {
1625        /**
1626         * Called from writeMapXml when an Object type is not recognized. The implementer
1627         * must write out the entire element including start and end tags.
1628         *
1629         * @param v The object to be written out
1630         * @param name The mapping key for v. Must be written into the "name" attribute of the
1631         *             start tag.
1632         * @param out The XML output stream.
1633         * @throws XmlPullParserException on unrecognized Object type.
1634         * @throws IOException on XmlSerializer serialization errors.
1635         * @hide
1636         */
1637         public void writeUnknownObject(Object v, String name, XmlSerializer out)
1638                 throws XmlPullParserException, IOException;
1639    }
1640
1641    /** @hide */
1642    public interface ReadMapCallback {
1643        /**
1644         * Called from readThisMapXml when a START_TAG is not recognized. The input stream
1645         * is positioned within the start tag so that attributes can be read using in.getAttribute.
1646         *
1647         * @param in the XML input stream
1648         * @param tag the START_TAG that was not recognized.
1649         * @return the Object parsed from the stream which will be put into the map.
1650         * @throws XmlPullParserException if the START_TAG is not recognized.
1651         * @throws IOException on XmlPullParser serialization errors.
1652         * @hide
1653         */
1654        public Object readThisUnknownObjectXml(XmlPullParser in, String tag)
1655                throws XmlPullParserException, IOException;
1656    }
1657}
1658