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