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