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 
skipCurrentTag(XmlPullParser parser)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
convertValueToList(CharSequence value, String[] options, int defaultValue)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
convertValueToBoolean(CharSequence value, boolean defaultValue)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
convertValueToInt(CharSequence charSeq, int defaultValue)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 
convertValueToUnsignedInt(String value, int defaultValue)131     public static int convertValueToUnsignedInt(String value, int defaultValue) {
132         if (null == value) {
133             return defaultValue;
134         }
135 
136         return parseUnsignedIntAttribute(value);
137     }
138 
parseUnsignedIntAttribute(CharSequence charSeq)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      */
writeMapXml(Map val, OutputStream out)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      */
writeListXml(List val, OutputStream out)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      */
writeMapXml(Map val, String name, XmlSerializer out)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      */
writeMapXml(Map val, String name, XmlSerializer out, WriteMapCallback callback)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      */
writeMapXml(Map val, XmlSerializer out, WriteMapCallback callback)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      */
writeListXml(List val, String name, XmlSerializer out)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 
writeSetXml(Set val, String name, XmlSerializer out)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      */
writeByteArrayXml(byte[] val, String name, XmlSerializer out)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      */
writeIntArrayXml(int[] val, String name, XmlSerializer out)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      */
writeLongArrayXml(long[] val, String name, XmlSerializer out)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      */
writeDoubleArrayXml(double[] val, String name, XmlSerializer out)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      */
writeStringArrayXml(String[] val, String name, XmlSerializer out)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      */
writeBooleanArrayXml(boolean[] val, String name, XmlSerializer out)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      */
writeValueXml(Object v, String name, XmlSerializer out)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      */
writeValueXml(Object v, String name, XmlSerializer out, WriteMapCallback callback)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")
readMapXml(InputStream in)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      */
readListXml(InputStream in)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      */
readSetXml(InputStream in)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      */
readThisMapXml(XmlPullParser parser, String endTag, String[] name)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      */
readThisMapXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback)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      */
readThisListXml(XmlPullParser parser, String endTag, String[] name)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      */
readThisListXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback)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      */
readThisSetXml(XmlPullParser parser, String endTag, String[] name)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      */
readThisSetXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback)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      */
readThisIntArrayXml(XmlPullParser parser, String endTag, String[] name)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      */
readThisLongArrayXml(XmlPullParser parser, String endTag, String[] name)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      */
readThisDoubleArrayXml(XmlPullParser parser, String endTag, String[] name)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      */
readThisStringArrayXml(XmlPullParser parser, String endTag, String[] name)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      */
readThisBooleanArrayXml(XmlPullParser parser, String endTag, String[] name)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      */
readValueXml(XmlPullParser parser, String[] name)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 
readThisValueXml(XmlPullParser parser, String[] name, ReadMapCallback callback)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 
readThisPrimitiveValueXml(XmlPullParser parser, String tagName)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 
beginDocument(XmlPullParser parser, String firstElementName)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 
nextElement(XmlPullParser parser)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 
nextElementWithin(XmlPullParser parser, int outerDepth)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 
readIntAttribute(XmlPullParser in, String name, int defaultValue)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 
readIntAttribute(XmlPullParser in, String name)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 
writeIntAttribute(XmlSerializer out, String name, int value)1503     public static void writeIntAttribute(XmlSerializer out, String name, int value)
1504             throws IOException {
1505         out.attribute(null, name, Integer.toString(value));
1506     }
1507 
readLongAttribute(XmlPullParser in, String name, long defaultValue)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 
readLongAttribute(XmlPullParser in, String name)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 
writeLongAttribute(XmlSerializer out, String name, long value)1526     public static void writeLongAttribute(XmlSerializer out, String name, long value)
1527             throws IOException {
1528         out.attribute(null, name, Long.toString(value));
1529     }
1530 
readFloatAttribute(XmlPullParser in, String name)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 
writeFloatAttribute(XmlSerializer out, String name, float value)1540     public static void writeFloatAttribute(XmlSerializer out, String name, float value)
1541             throws IOException {
1542         out.attribute(null, name, Float.toString(value));
1543     }
1544 
readBooleanAttribute(XmlPullParser in, String name)1545     public static boolean readBooleanAttribute(XmlPullParser in, String name) {
1546         final String value = in.getAttributeValue(null, name);
1547         return Boolean.parseBoolean(value);
1548     }
1549 
readBooleanAttribute(XmlPullParser in, String name, boolean defaultValue)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 
writeBooleanAttribute(XmlSerializer out, String name, boolean value)1560     public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
1561             throws IOException {
1562         out.attribute(null, name, Boolean.toString(value));
1563     }
1564 
readUriAttribute(XmlPullParser in, String name)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 
writeUriAttribute(XmlSerializer out, String name, Uri value)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 
readStringAttribute(XmlPullParser in, String name)1577     public static String readStringAttribute(XmlPullParser in, String name) {
1578         return in.getAttributeValue(null, name);
1579     }
1580 
writeStringAttribute(XmlSerializer out, String name, String value)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 
readByteArrayAttribute(XmlPullParser in, String name)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 
writeByteArrayAttribute(XmlSerializer out, String name, byte[] value)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 
readBitmapAttribute(XmlPullParser in, String name)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
writeBitmapAttribute(XmlSerializer out, String name, Bitmap value)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          */
writeUnknownObject(Object v, String name, XmlSerializer out)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          */
readThisUnknownObjectXml(XmlPullParser in, String tag)1654         public Object readThisUnknownObjectXml(XmlPullParser in, String tag)
1655                 throws XmlPullParserException, IOException;
1656     }
1657 }
1658