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