XmlUtils.java revision ded7b75d1a353856ad8f126d171d598d15b97760
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.util.Xml;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23import org.xmlpull.v1.XmlSerializer;
24
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.OutputStream;
28import java.net.ProtocolException;
29import java.util.ArrayList;
30import java.util.HashMap;
31import java.util.HashSet;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Map;
35import java.util.Set;
36
37/** {@hide} */
38public class XmlUtils {
39
40    public static void skipCurrentTag(XmlPullParser parser)
41            throws XmlPullParserException, IOException {
42        int outerDepth = parser.getDepth();
43        int type;
44        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
45               && (type != XmlPullParser.END_TAG
46                       || parser.getDepth() > outerDepth)) {
47        }
48    }
49
50    public static final int
51    convertValueToList(CharSequence value, String[] options, int defaultValue)
52    {
53        if (null != value) {
54            for (int i = 0; i < options.length; i++) {
55                if (value.equals(options[i]))
56                    return i;
57            }
58        }
59
60        return defaultValue;
61    }
62
63    public static final boolean
64    convertValueToBoolean(CharSequence value, boolean defaultValue)
65    {
66        boolean result = false;
67
68        if (null == value)
69            return defaultValue;
70
71        if (value.equals("1")
72        ||  value.equals("true")
73        ||  value.equals("TRUE"))
74            result = true;
75
76        return result;
77    }
78
79    public static final int
80    convertValueToInt(CharSequence charSeq, int defaultValue)
81    {
82        if (null == charSeq)
83            return defaultValue;
84
85        String nm = charSeq.toString();
86
87        // XXX This code is copied from Integer.decode() so we don't
88        // have to instantiate an Integer!
89
90        int value;
91        int sign = 1;
92        int index = 0;
93        int len = nm.length();
94        int base = 10;
95
96        if ('-' == nm.charAt(0)) {
97            sign = -1;
98            index++;
99        }
100
101        if ('0' == nm.charAt(index)) {
102            //  Quick check for a zero by itself
103            if (index == (len - 1))
104                return 0;
105
106            char    c = nm.charAt(index + 1);
107
108            if ('x' == c || 'X' == c) {
109                index += 2;
110                base = 16;
111            } else {
112                index++;
113                base = 8;
114            }
115        }
116        else if ('#' == nm.charAt(index))
117        {
118            index++;
119            base = 16;
120        }
121
122        return Integer.parseInt(nm.substring(index), base) * sign;
123    }
124
125    public static int convertValueToUnsignedInt(String value, int defaultValue) {
126        if (null == value) {
127            return defaultValue;
128        }
129
130        return parseUnsignedIntAttribute(value);
131    }
132
133    public static int parseUnsignedIntAttribute(CharSequence charSeq) {
134        String  value = charSeq.toString();
135
136        long    bits;
137        int     index = 0;
138        int     len = value.length();
139        int     base = 10;
140
141        if ('0' == value.charAt(index)) {
142            //  Quick check for zero by itself
143            if (index == (len - 1))
144                return 0;
145
146            char    c = value.charAt(index + 1);
147
148            if ('x' == c || 'X' == c) {     //  check for hex
149                index += 2;
150                base = 16;
151            } else {                        //  check for octal
152                index++;
153                base = 8;
154            }
155        } else if ('#' == value.charAt(index)) {
156            index++;
157            base = 16;
158        }
159
160        return (int) Long.parseLong(value.substring(index), base);
161    }
162
163    /**
164     * Flatten a Map into an output stream as XML.  The map can later be
165     * read back with readMapXml().
166     *
167     * @param val The map to be flattened.
168     * @param out Where to write the XML data.
169     *
170     * @see #writeMapXml(Map, String, XmlSerializer)
171     * @see #writeListXml
172     * @see #writeValueXml
173     * @see #readMapXml
174     */
175    public static final void writeMapXml(Map val, OutputStream out)
176            throws XmlPullParserException, java.io.IOException {
177        XmlSerializer serializer = new FastXmlSerializer();
178        serializer.setOutput(out, "utf-8");
179        serializer.startDocument(null, true);
180        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
181        writeMapXml(val, null, serializer);
182        serializer.endDocument();
183    }
184
185    /**
186     * Flatten a List into an output stream as XML.  The list can later be
187     * read back with readListXml().
188     *
189     * @param val The list to be flattened.
190     * @param out Where to write the XML data.
191     *
192     * @see #writeListXml(List, String, XmlSerializer)
193     * @see #writeMapXml
194     * @see #writeValueXml
195     * @see #readListXml
196     */
197    public static final void writeListXml(List val, OutputStream out)
198    throws XmlPullParserException, java.io.IOException
199    {
200        XmlSerializer serializer = Xml.newSerializer();
201        serializer.setOutput(out, "utf-8");
202        serializer.startDocument(null, true);
203        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
204        writeListXml(val, null, serializer);
205        serializer.endDocument();
206    }
207
208    /**
209     * Flatten a Map into an XmlSerializer.  The map can later be read back
210     * with readThisMapXml().
211     *
212     * @param val The map to be flattened.
213     * @param name Name attribute to include with this list's tag, or null for
214     *             none.
215     * @param out XmlSerializer to write the map into.
216     *
217     * @see #writeMapXml(Map, OutputStream)
218     * @see #writeListXml
219     * @see #writeValueXml
220     * @see #readMapXml
221     */
222    public static final void writeMapXml(Map val, String name, XmlSerializer out)
223    throws XmlPullParserException, java.io.IOException
224    {
225        if (val == null) {
226            out.startTag(null, "null");
227            out.endTag(null, "null");
228            return;
229        }
230
231        Set s = val.entrySet();
232        Iterator i = s.iterator();
233
234        out.startTag(null, "map");
235        if (name != null) {
236            out.attribute(null, "name", name);
237        }
238
239        while (i.hasNext()) {
240            Map.Entry e = (Map.Entry)i.next();
241            writeValueXml(e.getValue(), (String)e.getKey(), out);
242        }
243
244        out.endTag(null, "map");
245    }
246
247    /**
248     * Flatten a List into an XmlSerializer.  The list can later be read back
249     * with readThisListXml().
250     *
251     * @param val The list to be flattened.
252     * @param name Name attribute to include with this list's tag, or null for
253     *             none.
254     * @param out XmlSerializer to write the list into.
255     *
256     * @see #writeListXml(List, OutputStream)
257     * @see #writeMapXml
258     * @see #writeValueXml
259     * @see #readListXml
260     */
261    public static final void writeListXml(List val, String name, XmlSerializer out)
262    throws XmlPullParserException, java.io.IOException
263    {
264        if (val == null) {
265            out.startTag(null, "null");
266            out.endTag(null, "null");
267            return;
268        }
269
270        out.startTag(null, "list");
271        if (name != null) {
272            out.attribute(null, "name", name);
273        }
274
275        int N = val.size();
276        int i=0;
277        while (i < N) {
278            writeValueXml(val.get(i), null, out);
279            i++;
280        }
281
282        out.endTag(null, "list");
283    }
284
285    public static final void writeSetXml(Set val, String name, XmlSerializer out)
286            throws XmlPullParserException, java.io.IOException {
287        if (val == null) {
288            out.startTag(null, "null");
289            out.endTag(null, "null");
290            return;
291        }
292
293        out.startTag(null, "set");
294        if (name != null) {
295            out.attribute(null, "name", name);
296        }
297
298        for (Object v : val) {
299            writeValueXml(v, null, out);
300        }
301
302        out.endTag(null, "set");
303    }
304
305    /**
306     * Flatten a byte[] into an XmlSerializer.  The list can later be read back
307     * with readThisByteArrayXml().
308     *
309     * @param val The byte array to be flattened.
310     * @param name Name attribute to include with this array's tag, or null for
311     *             none.
312     * @param out XmlSerializer to write the array into.
313     *
314     * @see #writeMapXml
315     * @see #writeValueXml
316     */
317    public static final void writeByteArrayXml(byte[] val, String name,
318            XmlSerializer out)
319            throws XmlPullParserException, java.io.IOException {
320
321        if (val == null) {
322            out.startTag(null, "null");
323            out.endTag(null, "null");
324            return;
325        }
326
327        out.startTag(null, "byte-array");
328        if (name != null) {
329            out.attribute(null, "name", name);
330        }
331
332        final int N = val.length;
333        out.attribute(null, "num", Integer.toString(N));
334
335        StringBuilder sb = new StringBuilder(val.length*2);
336        for (int i=0; i<N; i++) {
337            int b = val[i];
338            int h = b>>4;
339            sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
340            h = b&0xff;
341            sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
342        }
343
344        out.text(sb.toString());
345
346        out.endTag(null, "byte-array");
347    }
348
349    /**
350     * Flatten an int[] into an XmlSerializer.  The list can later be read back
351     * with readThisIntArrayXml().
352     *
353     * @param val The int array to be flattened.
354     * @param name Name attribute to include with this array's tag, or null for
355     *             none.
356     * @param out XmlSerializer to write the array into.
357     *
358     * @see #writeMapXml
359     * @see #writeValueXml
360     * @see #readThisIntArrayXml
361     */
362    public static final void writeIntArrayXml(int[] val, String name,
363            XmlSerializer out)
364            throws XmlPullParserException, java.io.IOException {
365
366        if (val == null) {
367            out.startTag(null, "null");
368            out.endTag(null, "null");
369            return;
370        }
371
372        out.startTag(null, "int-array");
373        if (name != null) {
374            out.attribute(null, "name", name);
375        }
376
377        final int N = val.length;
378        out.attribute(null, "num", Integer.toString(N));
379
380        for (int i=0; i<N; i++) {
381            out.startTag(null, "item");
382            out.attribute(null, "value", Integer.toString(val[i]));
383            out.endTag(null, "item");
384        }
385
386        out.endTag(null, "int-array");
387    }
388
389    /**
390     * Flatten an object's value into an XmlSerializer.  The value can later
391     * be read back with readThisValueXml().
392     *
393     * Currently supported value types are: null, String, Integer, Long,
394     * Float, Double Boolean, Map, List.
395     *
396     * @param v The object to be flattened.
397     * @param name Name attribute to include with this value's tag, or null
398     *             for none.
399     * @param out XmlSerializer to write the object into.
400     *
401     * @see #writeMapXml
402     * @see #writeListXml
403     * @see #readValueXml
404     */
405    public static final void writeValueXml(Object v, String name, XmlSerializer out)
406    throws XmlPullParserException, java.io.IOException
407    {
408        String typeStr;
409        if (v == null) {
410            out.startTag(null, "null");
411            if (name != null) {
412                out.attribute(null, "name", name);
413            }
414            out.endTag(null, "null");
415            return;
416        } else if (v instanceof String) {
417            out.startTag(null, "string");
418            if (name != null) {
419                out.attribute(null, "name", name);
420            }
421            out.text(v.toString());
422            out.endTag(null, "string");
423            return;
424        } else if (v instanceof Integer) {
425            typeStr = "int";
426        } else if (v instanceof Long) {
427            typeStr = "long";
428        } else if (v instanceof Float) {
429            typeStr = "float";
430        } else if (v instanceof Double) {
431            typeStr = "double";
432        } else if (v instanceof Boolean) {
433            typeStr = "boolean";
434        } else if (v instanceof byte[]) {
435            writeByteArrayXml((byte[])v, name, out);
436            return;
437        } else if (v instanceof int[]) {
438            writeIntArrayXml((int[])v, name, out);
439            return;
440        } else if (v instanceof Map) {
441            writeMapXml((Map)v, name, out);
442            return;
443        } else if (v instanceof List) {
444            writeListXml((List)v, name, out);
445            return;
446        } else if (v instanceof Set) {
447            writeSetXml((Set)v, name, out);
448            return;
449        } else if (v instanceof CharSequence) {
450            // XXX This is to allow us to at least write something if
451            // we encounter styled text...  but it means we will drop all
452            // of the styling information. :(
453            out.startTag(null, "string");
454            if (name != null) {
455                out.attribute(null, "name", name);
456            }
457            out.text(v.toString());
458            out.endTag(null, "string");
459            return;
460        } else {
461            throw new RuntimeException("writeValueXml: unable to write value " + v);
462        }
463
464        out.startTag(null, typeStr);
465        if (name != null) {
466            out.attribute(null, "name", name);
467        }
468        out.attribute(null, "value", v.toString());
469        out.endTag(null, typeStr);
470    }
471
472    /**
473     * Read a HashMap from an InputStream containing XML.  The stream can
474     * previously have been written by writeMapXml().
475     *
476     * @param in The InputStream from which to read.
477     *
478     * @return HashMap The resulting map.
479     *
480     * @see #readListXml
481     * @see #readValueXml
482     * @see #readThisMapXml
483     * #see #writeMapXml
484     */
485    public static final HashMap readMapXml(InputStream in)
486    throws XmlPullParserException, java.io.IOException
487    {
488        XmlPullParser   parser = Xml.newPullParser();
489        parser.setInput(in, null);
490        return (HashMap)readValueXml(parser, new String[1]);
491    }
492
493    /**
494     * Read an ArrayList from an InputStream containing XML.  The stream can
495     * previously have been written by writeListXml().
496     *
497     * @param in The InputStream from which to read.
498     *
499     * @return ArrayList The resulting list.
500     *
501     * @see #readMapXml
502     * @see #readValueXml
503     * @see #readThisListXml
504     * @see #writeListXml
505     */
506    public static final ArrayList readListXml(InputStream in)
507    throws XmlPullParserException, java.io.IOException
508    {
509        XmlPullParser   parser = Xml.newPullParser();
510        parser.setInput(in, null);
511        return (ArrayList)readValueXml(parser, new String[1]);
512    }
513
514
515    /**
516     * Read a HashSet from an InputStream containing XML. The stream can
517     * previously have been written by writeSetXml().
518     *
519     * @param in The InputStream from which to read.
520     *
521     * @return HashSet The resulting set.
522     *
523     * @throws XmlPullParserException
524     * @throws java.io.IOException
525     *
526     * @see #readValueXml
527     * @see #readThisSetXml
528     * @see #writeSetXml
529     */
530    public static final HashSet readSetXml(InputStream in)
531            throws XmlPullParserException, java.io.IOException {
532        XmlPullParser parser = Xml.newPullParser();
533        parser.setInput(in, null);
534        return (HashSet) readValueXml(parser, new String[1]);
535    }
536
537    /**
538     * Read a HashMap object from an XmlPullParser.  The XML data could
539     * previously have been generated by writeMapXml().  The XmlPullParser
540     * must be positioned <em>after</em> the tag that begins the map.
541     *
542     * @param parser The XmlPullParser from which to read the map data.
543     * @param endTag Name of the tag that will end the map, usually "map".
544     * @param name An array of one string, used to return the name attribute
545     *             of the map's tag.
546     *
547     * @return HashMap The newly generated map.
548     *
549     * @see #readMapXml
550     */
551    public static final HashMap readThisMapXml(XmlPullParser parser, String endTag, String[] name)
552    throws XmlPullParserException, java.io.IOException
553    {
554        HashMap map = new HashMap();
555
556        int eventType = parser.getEventType();
557        do {
558            if (eventType == parser.START_TAG) {
559                Object val = readThisValueXml(parser, name);
560                if (name[0] != null) {
561                    //System.out.println("Adding to map: " + name + " -> " + val);
562                    map.put(name[0], val);
563                } else {
564                    throw new XmlPullParserException(
565                        "Map value without name attribute: " + parser.getName());
566                }
567            } else if (eventType == parser.END_TAG) {
568                if (parser.getName().equals(endTag)) {
569                    return map;
570                }
571                throw new XmlPullParserException(
572                    "Expected " + endTag + " end tag at: " + parser.getName());
573            }
574            eventType = parser.next();
575        } while (eventType != parser.END_DOCUMENT);
576
577        throw new XmlPullParserException(
578            "Document ended before " + endTag + " end tag");
579    }
580
581    /**
582     * Read an ArrayList object from an XmlPullParser.  The XML data could
583     * previously have been generated by writeListXml().  The XmlPullParser
584     * must be positioned <em>after</em> the tag that begins the list.
585     *
586     * @param parser The XmlPullParser from which to read the list data.
587     * @param endTag Name of the tag that will end the list, usually "list".
588     * @param name An array of one string, used to return the name attribute
589     *             of the list's tag.
590     *
591     * @return HashMap The newly generated list.
592     *
593     * @see #readListXml
594     */
595    public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, String[] name)
596    throws XmlPullParserException, java.io.IOException
597    {
598        ArrayList list = new ArrayList();
599
600        int eventType = parser.getEventType();
601        do {
602            if (eventType == parser.START_TAG) {
603                Object val = readThisValueXml(parser, name);
604                list.add(val);
605                //System.out.println("Adding to list: " + val);
606            } else if (eventType == parser.END_TAG) {
607                if (parser.getName().equals(endTag)) {
608                    return list;
609                }
610                throw new XmlPullParserException(
611                    "Expected " + endTag + " end tag at: " + parser.getName());
612            }
613            eventType = parser.next();
614        } while (eventType != parser.END_DOCUMENT);
615
616        throw new XmlPullParserException(
617            "Document ended before " + endTag + " end tag");
618    }
619
620    /**
621     * Read a HashSet object from an XmlPullParser. The XML data could previously
622     * have been generated by writeSetXml(). The XmlPullParser must be positioned
623     * <em>after</em> the tag that begins the set.
624     *
625     * @param parser The XmlPullParser from which to read the set data.
626     * @param endTag Name of the tag that will end the set, usually "set".
627     * @param name An array of one string, used to return the name attribute
628     *             of the set's tag.
629     *
630     * @return HashSet The newly generated set.
631     *
632     * @throws XmlPullParserException
633     * @throws java.io.IOException
634     *
635     * @see #readSetXml
636     */
637    public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name)
638            throws XmlPullParserException, java.io.IOException {
639        HashSet set = new HashSet();
640
641        int eventType = parser.getEventType();
642        do {
643            if (eventType == parser.START_TAG) {
644                Object val = readThisValueXml(parser, name);
645                set.add(val);
646                //System.out.println("Adding to set: " + val);
647            } else if (eventType == parser.END_TAG) {
648                if (parser.getName().equals(endTag)) {
649                    return set;
650                }
651                throw new XmlPullParserException(
652                        "Expected " + endTag + " end tag at: " + parser.getName());
653            }
654            eventType = parser.next();
655        } while (eventType != parser.END_DOCUMENT);
656
657        throw new XmlPullParserException(
658                "Document ended before " + endTag + " end tag");
659    }
660
661    /**
662     * Read an int[] object from an XmlPullParser.  The XML data could
663     * previously have been generated by writeIntArrayXml().  The XmlPullParser
664     * must be positioned <em>after</em> the tag that begins the list.
665     *
666     * @param parser The XmlPullParser from which to read the list data.
667     * @param endTag Name of the tag that will end the list, usually "list".
668     * @param name An array of one string, used to return the name attribute
669     *             of the list's tag.
670     *
671     * @return Returns a newly generated int[].
672     *
673     * @see #readListXml
674     */
675    public static final int[] readThisIntArrayXml(XmlPullParser parser,
676            String endTag, String[] name)
677            throws XmlPullParserException, java.io.IOException {
678
679        int num;
680        try {
681            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
682        } catch (NullPointerException e) {
683            throw new XmlPullParserException(
684                    "Need num attribute in byte-array");
685        } catch (NumberFormatException e) {
686            throw new XmlPullParserException(
687                    "Not a number in num attribute in byte-array");
688        }
689
690        int[] array = new int[num];
691        int i = 0;
692
693        int eventType = parser.getEventType();
694        do {
695            if (eventType == parser.START_TAG) {
696                if (parser.getName().equals("item")) {
697                    try {
698                        array[i] = Integer.parseInt(
699                                parser.getAttributeValue(null, "value"));
700                    } catch (NullPointerException e) {
701                        throw new XmlPullParserException(
702                                "Need value attribute in item");
703                    } catch (NumberFormatException e) {
704                        throw new XmlPullParserException(
705                                "Not a number in value attribute in item");
706                    }
707                } else {
708                    throw new XmlPullParserException(
709                            "Expected item tag at: " + parser.getName());
710                }
711            } else if (eventType == parser.END_TAG) {
712                if (parser.getName().equals(endTag)) {
713                    return array;
714                } else if (parser.getName().equals("item")) {
715                    i++;
716                } else {
717                    throw new XmlPullParserException(
718                        "Expected " + endTag + " end tag at: "
719                        + parser.getName());
720                }
721            }
722            eventType = parser.next();
723        } while (eventType != parser.END_DOCUMENT);
724
725        throw new XmlPullParserException(
726            "Document ended before " + endTag + " end tag");
727    }
728
729    /**
730     * Read a flattened object from an XmlPullParser.  The XML data could
731     * previously have been written with writeMapXml(), writeListXml(), or
732     * writeValueXml().  The XmlPullParser must be positioned <em>at</em> the
733     * tag that defines the value.
734     *
735     * @param parser The XmlPullParser from which to read the object.
736     * @param name An array of one string, used to return the name attribute
737     *             of the value's tag.
738     *
739     * @return Object The newly generated value object.
740     *
741     * @see #readMapXml
742     * @see #readListXml
743     * @see #writeValueXml
744     */
745    public static final Object readValueXml(XmlPullParser parser, String[] name)
746    throws XmlPullParserException, java.io.IOException
747    {
748        int eventType = parser.getEventType();
749        do {
750            if (eventType == parser.START_TAG) {
751                return readThisValueXml(parser, name);
752            } else if (eventType == parser.END_TAG) {
753                throw new XmlPullParserException(
754                    "Unexpected end tag at: " + parser.getName());
755            } else if (eventType == parser.TEXT) {
756                throw new XmlPullParserException(
757                    "Unexpected text: " + parser.getText());
758            }
759            eventType = parser.next();
760        } while (eventType != parser.END_DOCUMENT);
761
762        throw new XmlPullParserException(
763            "Unexpected end of document");
764    }
765
766    private static final Object readThisValueXml(XmlPullParser parser, String[] name)
767    throws XmlPullParserException, java.io.IOException
768    {
769        final String valueName = parser.getAttributeValue(null, "name");
770        final String tagName = parser.getName();
771
772        //System.out.println("Reading this value tag: " + tagName + ", name=" + valueName);
773
774        Object res;
775
776        if (tagName.equals("null")) {
777            res = null;
778        } else if (tagName.equals("string")) {
779            String value = "";
780            int eventType;
781            while ((eventType = parser.next()) != parser.END_DOCUMENT) {
782                if (eventType == parser.END_TAG) {
783                    if (parser.getName().equals("string")) {
784                        name[0] = valueName;
785                        //System.out.println("Returning value for " + valueName + ": " + value);
786                        return value;
787                    }
788                    throw new XmlPullParserException(
789                        "Unexpected end tag in <string>: " + parser.getName());
790                } else if (eventType == parser.TEXT) {
791                    value += parser.getText();
792                } else if (eventType == parser.START_TAG) {
793                    throw new XmlPullParserException(
794                        "Unexpected start tag in <string>: " + parser.getName());
795                }
796            }
797            throw new XmlPullParserException(
798                "Unexpected end of document in <string>");
799        } else if (tagName.equals("int")) {
800            res = Integer.parseInt(parser.getAttributeValue(null, "value"));
801        } else if (tagName.equals("long")) {
802            res = Long.valueOf(parser.getAttributeValue(null, "value"));
803        } else if (tagName.equals("float")) {
804            res = new Float(parser.getAttributeValue(null, "value"));
805        } else if (tagName.equals("double")) {
806            res = new Double(parser.getAttributeValue(null, "value"));
807        } else if (tagName.equals("boolean")) {
808            res = Boolean.valueOf(parser.getAttributeValue(null, "value"));
809        } else if (tagName.equals("int-array")) {
810            parser.next();
811            res = readThisIntArrayXml(parser, "int-array", name);
812            name[0] = valueName;
813            //System.out.println("Returning value for " + valueName + ": " + res);
814            return res;
815        } else if (tagName.equals("map")) {
816            parser.next();
817            res = readThisMapXml(parser, "map", name);
818            name[0] = valueName;
819            //System.out.println("Returning value for " + valueName + ": " + res);
820            return res;
821        } else if (tagName.equals("list")) {
822            parser.next();
823            res = readThisListXml(parser, "list", name);
824            name[0] = valueName;
825            //System.out.println("Returning value for " + valueName + ": " + res);
826            return res;
827        } else if (tagName.equals("set")) {
828            parser.next();
829            res = readThisSetXml(parser, "set", name);
830            name[0] = valueName;
831            //System.out.println("Returning value for " + valueName + ": " + res);
832            return res;
833        } else {
834            throw new XmlPullParserException(
835                "Unknown tag: " + tagName);
836        }
837
838        // Skip through to end tag.
839        int eventType;
840        while ((eventType = parser.next()) != parser.END_DOCUMENT) {
841            if (eventType == parser.END_TAG) {
842                if (parser.getName().equals(tagName)) {
843                    name[0] = valueName;
844                    //System.out.println("Returning value for " + valueName + ": " + res);
845                    return res;
846                }
847                throw new XmlPullParserException(
848                    "Unexpected end tag in <" + tagName + ">: " + parser.getName());
849            } else if (eventType == parser.TEXT) {
850                throw new XmlPullParserException(
851                "Unexpected text in <" + tagName + ">: " + parser.getName());
852            } else if (eventType == parser.START_TAG) {
853                throw new XmlPullParserException(
854                    "Unexpected start tag in <" + tagName + ">: " + parser.getName());
855            }
856        }
857        throw new XmlPullParserException(
858            "Unexpected end of document in <" + tagName + ">");
859    }
860
861    public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException
862    {
863        int type;
864        while ((type=parser.next()) != parser.START_TAG
865                   && type != parser.END_DOCUMENT) {
866            ;
867        }
868
869        if (type != parser.START_TAG) {
870            throw new XmlPullParserException("No start tag found");
871        }
872
873        if (!parser.getName().equals(firstElementName)) {
874            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
875                    ", expected " + firstElementName);
876        }
877    }
878
879    public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException
880    {
881        int type;
882        while ((type=parser.next()) != parser.START_TAG
883                   && type != parser.END_DOCUMENT) {
884            ;
885        }
886    }
887
888    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
889            throws IOException, XmlPullParserException {
890        for (;;) {
891            int type = parser.next();
892            if (type == XmlPullParser.END_DOCUMENT
893                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
894                return false;
895            }
896            if (type == XmlPullParser.START_TAG
897                    && parser.getDepth() == outerDepth + 1) {
898                return true;
899            }
900        }
901    }
902
903    public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
904        final String value = in.getAttributeValue(null, name);
905        try {
906            return Integer.parseInt(value);
907        } catch (NumberFormatException e) {
908            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
909        }
910    }
911
912    public static void writeIntAttribute(XmlSerializer out, String name, int value)
913            throws IOException {
914        out.attribute(null, name, Integer.toString(value));
915    }
916
917    public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
918        final String value = in.getAttributeValue(null, name);
919        try {
920            return Long.parseLong(value);
921        } catch (NumberFormatException e) {
922            throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
923        }
924    }
925
926    public static void writeLongAttribute(XmlSerializer out, String name, long value)
927            throws IOException {
928        out.attribute(null, name, Long.toString(value));
929    }
930
931    public static boolean readBooleanAttribute(XmlPullParser in, String name) {
932        final String value = in.getAttributeValue(null, name);
933        return Boolean.parseBoolean(value);
934    }
935
936    public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
937            throws IOException {
938        out.attribute(null, name, Boolean.toString(value));
939    }
940}
941