Home | History | Annotate | Download | only in util
      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 
     17 package com.android.internal.util;
     18 
     19 import android.graphics.Bitmap;
     20 import android.graphics.BitmapFactory;
     21 import android.graphics.Bitmap.CompressFormat;
     22 import android.net.Uri;
     23 import android.util.Base64;
     24 import android.util.Xml;
     25 
     26 import org.xmlpull.v1.XmlPullParser;
     27 import org.xmlpull.v1.XmlPullParserException;
     28 import org.xmlpull.v1.XmlSerializer;
     29 
     30 import java.io.ByteArrayOutputStream;
     31 import java.io.IOException;
     32 import java.io.InputStream;
     33 import java.io.OutputStream;
     34 import java.net.ProtocolException;
     35 import java.util.ArrayList;
     36 import java.util.HashMap;
     37 import java.util.HashSet;
     38 import java.util.Iterator;
     39 import java.util.List;
     40 import java.util.Map;
     41 import java.util.Set;
     42 
     43 /** {@hide} */
     44 public 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