1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.util; 18 19 import android.annotation.UnsupportedAppUsage; 20 import android.graphics.Bitmap; 21 import android.graphics.BitmapFactory; 22 import android.graphics.Bitmap.CompressFormat; 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 org.xmlpull.v1.XmlPullParser; 30 import org.xmlpull.v1.XmlPullParserException; 31 import org.xmlpull.v1.XmlSerializer; 32 33 import java.io.ByteArrayOutputStream; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.io.OutputStream; 37 import java.net.ProtocolException; 38 import java.nio.charset.StandardCharsets; 39 import java.util.ArrayList; 40 import java.util.HashMap; 41 import java.util.HashSet; 42 import java.util.Iterator; 43 import java.util.List; 44 import java.util.Map; 45 import java.util.Set; 46 47 /** {@hide} */ 48 public class XmlUtils { 49 50 private static final String STRING_ARRAY_SEPARATOR = ":"; 51 52 @UnsupportedAppUsage skipCurrentTag(XmlPullParser parser)53 public static void skipCurrentTag(XmlPullParser parser) 54 throws XmlPullParserException, IOException { 55 int outerDepth = parser.getDepth(); 56 int type; 57 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 58 && (type != XmlPullParser.END_TAG 59 || parser.getDepth() > outerDepth)) { 60 } 61 } 62 63 public static final int convertValueToList(CharSequence value, String[] options, int defaultValue)64 convertValueToList(CharSequence value, String[] options, int defaultValue) 65 { 66 if (!TextUtils.isEmpty(value)) { 67 for (int i = 0; i < options.length; i++) { 68 if (value.equals(options[i])) 69 return i; 70 } 71 } 72 73 return defaultValue; 74 } 75 76 @UnsupportedAppUsage 77 public static final boolean convertValueToBoolean(CharSequence value, boolean defaultValue)78 convertValueToBoolean(CharSequence value, boolean defaultValue) 79 { 80 boolean result = false; 81 82 if (TextUtils.isEmpty(value)) { 83 return defaultValue; 84 } 85 86 if (value.equals("1") 87 || value.equals("true") 88 || value.equals("TRUE")) 89 result = true; 90 91 return result; 92 } 93 94 @UnsupportedAppUsage 95 public static final int convertValueToInt(CharSequence charSeq, int defaultValue)96 convertValueToInt(CharSequence charSeq, int defaultValue) 97 { 98 if (TextUtils.isEmpty(charSeq)) { 99 return defaultValue; 100 } 101 102 String nm = charSeq.toString(); 103 104 // XXX This code is copied from Integer.decode() so we don't 105 // have to instantiate an Integer! 106 107 int value; 108 int sign = 1; 109 int index = 0; 110 int len = nm.length(); 111 int base = 10; 112 113 if ('-' == nm.charAt(0)) { 114 sign = -1; 115 index++; 116 } 117 118 if ('0' == nm.charAt(index)) { 119 // Quick check for a zero by itself 120 if (index == (len - 1)) 121 return 0; 122 123 char c = nm.charAt(index + 1); 124 125 if ('x' == c || 'X' == c) { 126 index += 2; 127 base = 16; 128 } else { 129 index++; 130 base = 8; 131 } 132 } 133 else if ('#' == nm.charAt(index)) 134 { 135 index++; 136 base = 16; 137 } 138 139 return Integer.parseInt(nm.substring(index), base) * sign; 140 } 141 convertValueToUnsignedInt(String value, int defaultValue)142 public static int convertValueToUnsignedInt(String value, int defaultValue) { 143 if (TextUtils.isEmpty(value)) { 144 return defaultValue; 145 } 146 147 return parseUnsignedIntAttribute(value); 148 } 149 parseUnsignedIntAttribute(CharSequence charSeq)150 public static int parseUnsignedIntAttribute(CharSequence charSeq) { 151 String value = charSeq.toString(); 152 153 long bits; 154 int index = 0; 155 int len = value.length(); 156 int base = 10; 157 158 if ('0' == value.charAt(index)) { 159 // Quick check for zero by itself 160 if (index == (len - 1)) 161 return 0; 162 163 char c = value.charAt(index + 1); 164 165 if ('x' == c || 'X' == c) { // check for hex 166 index += 2; 167 base = 16; 168 } else { // check for octal 169 index++; 170 base = 8; 171 } 172 } else if ('#' == value.charAt(index)) { 173 index++; 174 base = 16; 175 } 176 177 return (int) Long.parseLong(value.substring(index), base); 178 } 179 180 /** 181 * Flatten a Map into an output stream as XML. The map can later be 182 * read back with readMapXml(). 183 * 184 * @param val The map to be flattened. 185 * @param out Where to write the XML data. 186 * 187 * @see #writeMapXml(Map, String, XmlSerializer) 188 * @see #writeListXml 189 * @see #writeValueXml 190 * @see #readMapXml 191 */ 192 @UnsupportedAppUsage writeMapXml(Map val, OutputStream out)193 public static final void writeMapXml(Map val, OutputStream out) 194 throws XmlPullParserException, java.io.IOException { 195 XmlSerializer serializer = new FastXmlSerializer(); 196 serializer.setOutput(out, StandardCharsets.UTF_8.name()); 197 serializer.startDocument(null, true); 198 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 199 writeMapXml(val, null, serializer); 200 serializer.endDocument(); 201 } 202 203 /** 204 * Flatten a List into an output stream as XML. The list can later be 205 * read back with readListXml(). 206 * 207 * @param val The list to be flattened. 208 * @param out Where to write the XML data. 209 * 210 * @see #writeListXml(List, String, XmlSerializer) 211 * @see #writeMapXml 212 * @see #writeValueXml 213 * @see #readListXml 214 */ writeListXml(List val, OutputStream out)215 public static final void writeListXml(List val, OutputStream out) 216 throws XmlPullParserException, java.io.IOException 217 { 218 XmlSerializer serializer = Xml.newSerializer(); 219 serializer.setOutput(out, StandardCharsets.UTF_8.name()); 220 serializer.startDocument(null, true); 221 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 222 writeListXml(val, null, serializer); 223 serializer.endDocument(); 224 } 225 226 /** 227 * Flatten a Map into an XmlSerializer. The map can later be read back 228 * with readThisMapXml(). 229 * 230 * @param val The map to be flattened. 231 * @param name Name attribute to include with this list's tag, or null for 232 * none. 233 * @param out XmlSerializer to write the map into. 234 * 235 * @see #writeMapXml(Map, OutputStream) 236 * @see #writeListXml 237 * @see #writeValueXml 238 * @see #readMapXml 239 */ writeMapXml(Map val, String name, XmlSerializer out)240 public static final void writeMapXml(Map val, String name, XmlSerializer out) 241 throws XmlPullParserException, java.io.IOException { 242 writeMapXml(val, name, out, null); 243 } 244 245 /** 246 * Flatten a Map into an XmlSerializer. The map can later be read back 247 * with readThisMapXml(). 248 * 249 * @param val The map to be flattened. 250 * @param name Name attribute to include with this list's tag, or null for 251 * none. 252 * @param out XmlSerializer to write the map into. 253 * @param callback Method to call when an Object type is not recognized. 254 * 255 * @see #writeMapXml(Map, OutputStream) 256 * @see #writeListXml 257 * @see #writeValueXml 258 * @see #readMapXml 259 * 260 * @hide 261 */ writeMapXml(Map val, String name, XmlSerializer out, WriteMapCallback callback)262 public static final void writeMapXml(Map val, String name, XmlSerializer out, 263 WriteMapCallback callback) throws XmlPullParserException, java.io.IOException { 264 265 if (val == null) { 266 out.startTag(null, "null"); 267 out.endTag(null, "null"); 268 return; 269 } 270 271 out.startTag(null, "map"); 272 if (name != null) { 273 out.attribute(null, "name", name); 274 } 275 276 writeMapXml(val, out, callback); 277 278 out.endTag(null, "map"); 279 } 280 281 /** 282 * Flatten a Map into an XmlSerializer. The map can later be read back 283 * with readThisMapXml(). This method presumes that the start tag and 284 * name attribute have already been written and does not write an end tag. 285 * 286 * @param val The map to be flattened. 287 * @param out XmlSerializer to write the map into. 288 * 289 * @see #writeMapXml(Map, OutputStream) 290 * @see #writeListXml 291 * @see #writeValueXml 292 * @see #readMapXml 293 * 294 * @hide 295 */ writeMapXml(Map val, XmlSerializer out, WriteMapCallback callback)296 public static final void writeMapXml(Map val, XmlSerializer out, 297 WriteMapCallback callback) throws XmlPullParserException, java.io.IOException { 298 if (val == null) { 299 return; 300 } 301 302 Set s = val.entrySet(); 303 Iterator i = s.iterator(); 304 305 while (i.hasNext()) { 306 Map.Entry e = (Map.Entry)i.next(); 307 writeValueXml(e.getValue(), (String)e.getKey(), out, callback); 308 } 309 } 310 311 /** 312 * Flatten a List into an XmlSerializer. The list can later be read back 313 * with readThisListXml(). 314 * 315 * @param val The list to be flattened. 316 * @param name Name attribute to include with this list's tag, or null for 317 * none. 318 * @param out XmlSerializer to write the list into. 319 * 320 * @see #writeListXml(List, OutputStream) 321 * @see #writeMapXml 322 * @see #writeValueXml 323 * @see #readListXml 324 */ writeListXml(List val, String name, XmlSerializer out)325 public static final void writeListXml(List val, String name, XmlSerializer out) 326 throws XmlPullParserException, java.io.IOException 327 { 328 if (val == null) { 329 out.startTag(null, "null"); 330 out.endTag(null, "null"); 331 return; 332 } 333 334 out.startTag(null, "list"); 335 if (name != null) { 336 out.attribute(null, "name", name); 337 } 338 339 int N = val.size(); 340 int i=0; 341 while (i < N) { 342 writeValueXml(val.get(i), null, out); 343 i++; 344 } 345 346 out.endTag(null, "list"); 347 } 348 writeSetXml(Set val, String name, XmlSerializer out)349 public static final void writeSetXml(Set val, String name, XmlSerializer out) 350 throws XmlPullParserException, java.io.IOException { 351 if (val == null) { 352 out.startTag(null, "null"); 353 out.endTag(null, "null"); 354 return; 355 } 356 357 out.startTag(null, "set"); 358 if (name != null) { 359 out.attribute(null, "name", name); 360 } 361 362 for (Object v : val) { 363 writeValueXml(v, null, out); 364 } 365 366 out.endTag(null, "set"); 367 } 368 369 /** 370 * Flatten a byte[] into an XmlSerializer. The list can later be read back 371 * with readThisByteArrayXml(). 372 * 373 * @param val The byte array to be flattened. 374 * @param name Name attribute to include with this array's tag, or null for 375 * none. 376 * @param out XmlSerializer to write the array into. 377 * 378 * @see #writeMapXml 379 * @see #writeValueXml 380 */ writeByteArrayXml(byte[] val, String name, XmlSerializer out)381 public static final void writeByteArrayXml(byte[] val, String name, 382 XmlSerializer out) 383 throws XmlPullParserException, java.io.IOException { 384 385 if (val == null) { 386 out.startTag(null, "null"); 387 out.endTag(null, "null"); 388 return; 389 } 390 391 out.startTag(null, "byte-array"); 392 if (name != null) { 393 out.attribute(null, "name", name); 394 } 395 396 final int N = val.length; 397 out.attribute(null, "num", Integer.toString(N)); 398 399 StringBuilder sb = new StringBuilder(val.length*2); 400 for (int i=0; i<N; i++) { 401 int b = val[i]; 402 int h = (b >> 4) & 0x0f; 403 sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h))); 404 h = b & 0x0f; 405 sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h))); 406 } 407 408 out.text(sb.toString()); 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, java.io.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, java.io.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, java.io.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, java.io.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, java.io.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, java.io.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, java.io.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, java.io.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, java.io.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 java.io.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, java.io.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, java.io.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, java.io.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, java.io.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, java.io.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, java.io.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 java.io.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, java.io.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 java.io.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, java.io.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, java.io.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 byte[] array = new byte[num]; 1036 1037 int eventType = parser.getEventType(); 1038 do { 1039 if (eventType == parser.TEXT) { 1040 if (num > 0) { 1041 String values = parser.getText(); 1042 if (values == null || values.length() != num * 2) { 1043 throw new XmlPullParserException( 1044 "Invalid value found in byte-array: " + values); 1045 } 1046 // This is ugly, but keeping it to mirror the logic in #writeByteArrayXml. 1047 for (int i = 0; i < num; i ++) { 1048 char nibbleHighChar = values.charAt(2 * i); 1049 char nibbleLowChar = values.charAt(2 * i + 1); 1050 int nibbleHigh = nibbleHighChar > 'a' ? (nibbleHighChar - 'a' + 10) 1051 : (nibbleHighChar - '0'); 1052 int nibbleLow = nibbleLowChar > 'a' ? (nibbleLowChar - 'a' + 10) 1053 : (nibbleLowChar - '0'); 1054 array[i] = (byte) ((nibbleHigh & 0x0F) << 4 | (nibbleLow & 0x0F)); 1055 } 1056 } 1057 } else if (eventType == parser.END_TAG) { 1058 if (parser.getName().equals(endTag)) { 1059 return array; 1060 } else { 1061 throw new XmlPullParserException( 1062 "Expected " + endTag + " end tag at: " 1063 + parser.getName()); 1064 } 1065 } 1066 eventType = parser.next(); 1067 } while (eventType != parser.END_DOCUMENT); 1068 1069 throw new XmlPullParserException( 1070 "Document ended before " + endTag + " end tag"); 1071 } 1072 1073 /** 1074 * Read an int[] object from an XmlPullParser. The XML data could 1075 * previously have been generated by writeIntArrayXml(). The XmlPullParser 1076 * must be positioned <em>after</em> the tag that begins the list. 1077 * 1078 * @param parser The XmlPullParser from which to read the list data. 1079 * @param endTag Name of the tag that will end the list, usually "list". 1080 * @param name An array of one string, used to return the name attribute 1081 * of the list's tag. 1082 * 1083 * @return Returns a newly generated int[]. 1084 * 1085 * @see #readListXml 1086 */ readThisIntArrayXml(XmlPullParser parser, String endTag, String[] name)1087 public static final int[] readThisIntArrayXml(XmlPullParser parser, 1088 String endTag, String[] name) 1089 throws XmlPullParserException, java.io.IOException { 1090 1091 int num; 1092 try { 1093 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1094 } catch (NullPointerException e) { 1095 throw new XmlPullParserException( 1096 "Need num attribute in int-array"); 1097 } catch (NumberFormatException e) { 1098 throw new XmlPullParserException( 1099 "Not a number in num attribute in int-array"); 1100 } 1101 parser.next(); 1102 1103 int[] array = new int[num]; 1104 int i = 0; 1105 1106 int eventType = parser.getEventType(); 1107 do { 1108 if (eventType == parser.START_TAG) { 1109 if (parser.getName().equals("item")) { 1110 try { 1111 array[i] = Integer.parseInt( 1112 parser.getAttributeValue(null, "value")); 1113 } catch (NullPointerException e) { 1114 throw new XmlPullParserException( 1115 "Need value attribute in item"); 1116 } catch (NumberFormatException e) { 1117 throw new XmlPullParserException( 1118 "Not a number in value attribute in item"); 1119 } 1120 } else { 1121 throw new XmlPullParserException( 1122 "Expected item tag at: " + parser.getName()); 1123 } 1124 } else if (eventType == parser.END_TAG) { 1125 if (parser.getName().equals(endTag)) { 1126 return array; 1127 } else if (parser.getName().equals("item")) { 1128 i++; 1129 } else { 1130 throw new XmlPullParserException( 1131 "Expected " + endTag + " end tag at: " 1132 + parser.getName()); 1133 } 1134 } 1135 eventType = parser.next(); 1136 } while (eventType != parser.END_DOCUMENT); 1137 1138 throw new XmlPullParserException( 1139 "Document ended before " + endTag + " end tag"); 1140 } 1141 1142 /** 1143 * Read a long[] object from an XmlPullParser. The XML data could 1144 * previously have been generated by writeLongArrayXml(). The XmlPullParser 1145 * must be positioned <em>after</em> the tag that begins the list. 1146 * 1147 * @param parser The XmlPullParser from which to read the list data. 1148 * @param endTag Name of the tag that will end the list, usually "list". 1149 * @param name An array of one string, used to return the name attribute 1150 * of the list's tag. 1151 * 1152 * @return Returns a newly generated long[]. 1153 * 1154 * @see #readListXml 1155 */ readThisLongArrayXml(XmlPullParser parser, String endTag, String[] name)1156 public static final long[] readThisLongArrayXml(XmlPullParser parser, 1157 String endTag, String[] name) 1158 throws XmlPullParserException, java.io.IOException { 1159 1160 int num; 1161 try { 1162 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1163 } catch (NullPointerException e) { 1164 throw new XmlPullParserException("Need num attribute in long-array"); 1165 } catch (NumberFormatException e) { 1166 throw new XmlPullParserException("Not a number in num attribute in long-array"); 1167 } 1168 parser.next(); 1169 1170 long[] array = new long[num]; 1171 int i = 0; 1172 1173 int eventType = parser.getEventType(); 1174 do { 1175 if (eventType == parser.START_TAG) { 1176 if (parser.getName().equals("item")) { 1177 try { 1178 array[i] = Long.parseLong(parser.getAttributeValue(null, "value")); 1179 } catch (NullPointerException e) { 1180 throw new XmlPullParserException("Need value attribute in item"); 1181 } catch (NumberFormatException e) { 1182 throw new XmlPullParserException("Not a number in value attribute in item"); 1183 } 1184 } else { 1185 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 1186 } 1187 } else if (eventType == parser.END_TAG) { 1188 if (parser.getName().equals(endTag)) { 1189 return array; 1190 } else if (parser.getName().equals("item")) { 1191 i++; 1192 } else { 1193 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + 1194 parser.getName()); 1195 } 1196 } 1197 eventType = parser.next(); 1198 } while (eventType != parser.END_DOCUMENT); 1199 1200 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 1201 } 1202 1203 /** 1204 * Read a double[] object from an XmlPullParser. The XML data could 1205 * previously have been generated by writeDoubleArrayXml(). The XmlPullParser 1206 * must be positioned <em>after</em> the tag that begins the list. 1207 * 1208 * @param parser The XmlPullParser from which to read the list data. 1209 * @param endTag Name of the tag that will end the list, usually "double-array". 1210 * @param name An array of one string, used to return the name attribute 1211 * of the list's tag. 1212 * 1213 * @return Returns a newly generated double[]. 1214 * 1215 * @see #readListXml 1216 */ readThisDoubleArrayXml(XmlPullParser parser, String endTag, String[] name)1217 public static final double[] readThisDoubleArrayXml(XmlPullParser parser, String endTag, 1218 String[] name) throws XmlPullParserException, java.io.IOException { 1219 1220 int num; 1221 try { 1222 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1223 } catch (NullPointerException e) { 1224 throw new XmlPullParserException("Need num attribute in double-array"); 1225 } catch (NumberFormatException e) { 1226 throw new XmlPullParserException("Not a number in num attribute in double-array"); 1227 } 1228 parser.next(); 1229 1230 double[] array = new double[num]; 1231 int i = 0; 1232 1233 int eventType = parser.getEventType(); 1234 do { 1235 if (eventType == parser.START_TAG) { 1236 if (parser.getName().equals("item")) { 1237 try { 1238 array[i] = Double.parseDouble(parser.getAttributeValue(null, "value")); 1239 } catch (NullPointerException e) { 1240 throw new XmlPullParserException("Need value attribute in item"); 1241 } catch (NumberFormatException e) { 1242 throw new XmlPullParserException("Not a number in value attribute in item"); 1243 } 1244 } else { 1245 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 1246 } 1247 } else if (eventType == parser.END_TAG) { 1248 if (parser.getName().equals(endTag)) { 1249 return array; 1250 } else if (parser.getName().equals("item")) { 1251 i++; 1252 } else { 1253 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + 1254 parser.getName()); 1255 } 1256 } 1257 eventType = parser.next(); 1258 } while (eventType != parser.END_DOCUMENT); 1259 1260 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 1261 } 1262 1263 /** 1264 * Read a String[] object from an XmlPullParser. The XML data could 1265 * previously have been generated by writeStringArrayXml(). The XmlPullParser 1266 * must be positioned <em>after</em> the tag that begins the list. 1267 * 1268 * @param parser The XmlPullParser from which to read the list data. 1269 * @param endTag Name of the tag that will end the list, usually "string-array". 1270 * @param name An array of one string, used to return the name attribute 1271 * of the list's tag. 1272 * 1273 * @return Returns a newly generated String[]. 1274 * 1275 * @see #readListXml 1276 */ readThisStringArrayXml(XmlPullParser parser, String endTag, String[] name)1277 public static final String[] readThisStringArrayXml(XmlPullParser parser, String endTag, 1278 String[] name) throws XmlPullParserException, java.io.IOException { 1279 1280 int num; 1281 try { 1282 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1283 } catch (NullPointerException e) { 1284 throw new XmlPullParserException("Need num attribute in string-array"); 1285 } catch (NumberFormatException e) { 1286 throw new XmlPullParserException("Not a number in num attribute in string-array"); 1287 } 1288 parser.next(); 1289 1290 String[] array = new String[num]; 1291 int i = 0; 1292 1293 int eventType = parser.getEventType(); 1294 do { 1295 if (eventType == parser.START_TAG) { 1296 if (parser.getName().equals("item")) { 1297 try { 1298 array[i] = parser.getAttributeValue(null, "value"); 1299 } catch (NullPointerException e) { 1300 throw new XmlPullParserException("Need value attribute in item"); 1301 } catch (NumberFormatException e) { 1302 throw new XmlPullParserException("Not a number in value attribute in item"); 1303 } 1304 } else { 1305 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 1306 } 1307 } else if (eventType == parser.END_TAG) { 1308 if (parser.getName().equals(endTag)) { 1309 return array; 1310 } else if (parser.getName().equals("item")) { 1311 i++; 1312 } else { 1313 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + 1314 parser.getName()); 1315 } 1316 } 1317 eventType = parser.next(); 1318 } while (eventType != parser.END_DOCUMENT); 1319 1320 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 1321 } 1322 1323 /** 1324 * Read a boolean[] object from an XmlPullParser. The XML data could 1325 * previously have been generated by writeBooleanArrayXml(). The XmlPullParser 1326 * must be positioned <em>after</em> the tag that begins the list. 1327 * 1328 * @param parser The XmlPullParser from which to read the list data. 1329 * @param endTag Name of the tag that will end the list, usually "string-array". 1330 * @param name An array of one string, used to return the name attribute 1331 * of the list's tag. 1332 * 1333 * @return Returns a newly generated boolean[]. 1334 * 1335 * @see #readListXml 1336 */ readThisBooleanArrayXml(XmlPullParser parser, String endTag, String[] name)1337 public static final boolean[] readThisBooleanArrayXml(XmlPullParser parser, String endTag, 1338 String[] name) throws XmlPullParserException, java.io.IOException { 1339 1340 int num; 1341 try { 1342 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1343 } catch (NullPointerException e) { 1344 throw new XmlPullParserException("Need num attribute in string-array"); 1345 } catch (NumberFormatException e) { 1346 throw new XmlPullParserException("Not a number in num attribute in string-array"); 1347 } 1348 parser.next(); 1349 1350 boolean[] array = new boolean[num]; 1351 int i = 0; 1352 1353 int eventType = parser.getEventType(); 1354 do { 1355 if (eventType == parser.START_TAG) { 1356 if (parser.getName().equals("item")) { 1357 try { 1358 array[i] = Boolean.parseBoolean(parser.getAttributeValue(null, "value")); 1359 } catch (NullPointerException e) { 1360 throw new XmlPullParserException("Need value attribute in item"); 1361 } catch (NumberFormatException e) { 1362 throw new XmlPullParserException("Not a number in value attribute in item"); 1363 } 1364 } else { 1365 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 1366 } 1367 } else if (eventType == parser.END_TAG) { 1368 if (parser.getName().equals(endTag)) { 1369 return array; 1370 } else if (parser.getName().equals("item")) { 1371 i++; 1372 } else { 1373 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + 1374 parser.getName()); 1375 } 1376 } 1377 eventType = parser.next(); 1378 } while (eventType != parser.END_DOCUMENT); 1379 1380 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 1381 } 1382 1383 /** 1384 * Read a flattened object from an XmlPullParser. The XML data could 1385 * previously have been written with writeMapXml(), writeListXml(), or 1386 * writeValueXml(). The XmlPullParser must be positioned <em>at</em> the 1387 * tag that defines the value. 1388 * 1389 * @param parser The XmlPullParser from which to read the object. 1390 * @param name An array of one string, used to return the name attribute 1391 * of the value's tag. 1392 * 1393 * @return Object The newly generated value object. 1394 * 1395 * @see #readMapXml 1396 * @see #readListXml 1397 * @see #writeValueXml 1398 */ readValueXml(XmlPullParser parser, String[] name)1399 public static final Object readValueXml(XmlPullParser parser, String[] name) 1400 throws XmlPullParserException, java.io.IOException 1401 { 1402 int eventType = parser.getEventType(); 1403 do { 1404 if (eventType == parser.START_TAG) { 1405 return readThisValueXml(parser, name, null, false); 1406 } else if (eventType == parser.END_TAG) { 1407 throw new XmlPullParserException( 1408 "Unexpected end tag at: " + parser.getName()); 1409 } else if (eventType == parser.TEXT) { 1410 throw new XmlPullParserException( 1411 "Unexpected text: " + parser.getText()); 1412 } 1413 eventType = parser.next(); 1414 } while (eventType != parser.END_DOCUMENT); 1415 1416 throw new XmlPullParserException( 1417 "Unexpected end of document"); 1418 } 1419 readThisValueXml(XmlPullParser parser, String[] name, ReadMapCallback callback, boolean arrayMap)1420 private static final Object readThisValueXml(XmlPullParser parser, String[] name, 1421 ReadMapCallback callback, boolean arrayMap) 1422 throws XmlPullParserException, java.io.IOException { 1423 final String valueName = parser.getAttributeValue(null, "name"); 1424 final String tagName = parser.getName(); 1425 1426 //System.out.println("Reading this value tag: " + tagName + ", name=" + valueName); 1427 1428 Object res; 1429 1430 if (tagName.equals("null")) { 1431 res = null; 1432 } else if (tagName.equals("string")) { 1433 String value = ""; 1434 int eventType; 1435 while ((eventType = parser.next()) != parser.END_DOCUMENT) { 1436 if (eventType == parser.END_TAG) { 1437 if (parser.getName().equals("string")) { 1438 name[0] = valueName; 1439 //System.out.println("Returning value for " + valueName + ": " + value); 1440 return value; 1441 } 1442 throw new XmlPullParserException( 1443 "Unexpected end tag in <string>: " + parser.getName()); 1444 } else if (eventType == parser.TEXT) { 1445 value += parser.getText(); 1446 } else if (eventType == parser.START_TAG) { 1447 throw new XmlPullParserException( 1448 "Unexpected start tag in <string>: " + parser.getName()); 1449 } 1450 } 1451 throw new XmlPullParserException( 1452 "Unexpected end of document in <string>"); 1453 } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) { 1454 // all work already done by readThisPrimitiveValueXml 1455 } else if (tagName.equals("byte-array")) { 1456 res = readThisByteArrayXml(parser, "byte-array", name); 1457 name[0] = valueName; 1458 //System.out.println("Returning value for " + valueName + ": " + res); 1459 return res; 1460 } else if (tagName.equals("int-array")) { 1461 res = readThisIntArrayXml(parser, "int-array", name); 1462 name[0] = valueName; 1463 //System.out.println("Returning value for " + valueName + ": " + res); 1464 return res; 1465 } else if (tagName.equals("long-array")) { 1466 res = readThisLongArrayXml(parser, "long-array", name); 1467 name[0] = valueName; 1468 //System.out.println("Returning value for " + valueName + ": " + res); 1469 return res; 1470 } else if (tagName.equals("double-array")) { 1471 res = readThisDoubleArrayXml(parser, "double-array", name); 1472 name[0] = valueName; 1473 //System.out.println("Returning value for " + valueName + ": " + res); 1474 return res; 1475 } else if (tagName.equals("string-array")) { 1476 res = readThisStringArrayXml(parser, "string-array", name); 1477 name[0] = valueName; 1478 //System.out.println("Returning value for " + valueName + ": " + res); 1479 return res; 1480 } else if (tagName.equals("boolean-array")) { 1481 res = readThisBooleanArrayXml(parser, "boolean-array", name); 1482 name[0] = valueName; 1483 //System.out.println("Returning value for " + valueName + ": " + res); 1484 return res; 1485 } else if (tagName.equals("map")) { 1486 parser.next(); 1487 res = arrayMap 1488 ? readThisArrayMapXml(parser, "map", name, callback) 1489 : readThisMapXml(parser, "map", name, callback); 1490 name[0] = valueName; 1491 //System.out.println("Returning value for " + valueName + ": " + res); 1492 return res; 1493 } else if (tagName.equals("list")) { 1494 parser.next(); 1495 res = readThisListXml(parser, "list", name, callback, arrayMap); 1496 name[0] = valueName; 1497 //System.out.println("Returning value for " + valueName + ": " + res); 1498 return res; 1499 } else if (tagName.equals("set")) { 1500 parser.next(); 1501 res = readThisSetXml(parser, "set", name, callback, arrayMap); 1502 name[0] = valueName; 1503 //System.out.println("Returning value for " + valueName + ": " + res); 1504 return res; 1505 } else if (callback != null) { 1506 res = callback.readThisUnknownObjectXml(parser, tagName); 1507 name[0] = valueName; 1508 return res; 1509 } else { 1510 throw new XmlPullParserException("Unknown tag: " + tagName); 1511 } 1512 1513 // Skip through to end tag. 1514 int eventType; 1515 while ((eventType = parser.next()) != parser.END_DOCUMENT) { 1516 if (eventType == parser.END_TAG) { 1517 if (parser.getName().equals(tagName)) { 1518 name[0] = valueName; 1519 //System.out.println("Returning value for " + valueName + ": " + res); 1520 return res; 1521 } 1522 throw new XmlPullParserException( 1523 "Unexpected end tag in <" + tagName + ">: " + parser.getName()); 1524 } else if (eventType == parser.TEXT) { 1525 throw new XmlPullParserException( 1526 "Unexpected text in <" + tagName + ">: " + parser.getName()); 1527 } else if (eventType == parser.START_TAG) { 1528 throw new XmlPullParserException( 1529 "Unexpected start tag in <" + tagName + ">: " + parser.getName()); 1530 } 1531 } 1532 throw new XmlPullParserException( 1533 "Unexpected end of document in <" + tagName + ">"); 1534 } 1535 readThisPrimitiveValueXml(XmlPullParser parser, String tagName)1536 private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName) 1537 throws XmlPullParserException, java.io.IOException 1538 { 1539 try { 1540 if (tagName.equals("int")) { 1541 return Integer.parseInt(parser.getAttributeValue(null, "value")); 1542 } else if (tagName.equals("long")) { 1543 return Long.valueOf(parser.getAttributeValue(null, "value")); 1544 } else if (tagName.equals("float")) { 1545 return new Float(parser.getAttributeValue(null, "value")); 1546 } else if (tagName.equals("double")) { 1547 return new Double(parser.getAttributeValue(null, "value")); 1548 } else if (tagName.equals("boolean")) { 1549 return Boolean.valueOf(parser.getAttributeValue(null, "value")); 1550 } else { 1551 return null; 1552 } 1553 } catch (NullPointerException e) { 1554 throw new XmlPullParserException("Need value attribute in <" + tagName + ">"); 1555 } catch (NumberFormatException e) { 1556 throw new XmlPullParserException( 1557 "Not a number in value attribute in <" + tagName + ">"); 1558 } 1559 } 1560 1561 @UnsupportedAppUsage beginDocument(XmlPullParser parser, String firstElementName)1562 public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException 1563 { 1564 int type; 1565 while ((type=parser.next()) != parser.START_TAG 1566 && type != parser.END_DOCUMENT) { 1567 ; 1568 } 1569 1570 if (type != parser.START_TAG) { 1571 throw new XmlPullParserException("No start tag found"); 1572 } 1573 1574 if (!parser.getName().equals(firstElementName)) { 1575 throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() + 1576 ", expected " + firstElementName); 1577 } 1578 } 1579 1580 @UnsupportedAppUsage nextElement(XmlPullParser parser)1581 public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException 1582 { 1583 int type; 1584 while ((type=parser.next()) != parser.START_TAG 1585 && type != parser.END_DOCUMENT) { 1586 ; 1587 } 1588 } 1589 nextElementWithin(XmlPullParser parser, int outerDepth)1590 public static boolean nextElementWithin(XmlPullParser parser, int outerDepth) 1591 throws IOException, XmlPullParserException { 1592 for (;;) { 1593 int type = parser.next(); 1594 if (type == XmlPullParser.END_DOCUMENT 1595 || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) { 1596 return false; 1597 } 1598 if (type == XmlPullParser.START_TAG 1599 && parser.getDepth() == outerDepth + 1) { 1600 return true; 1601 } 1602 } 1603 } 1604 readIntAttribute(XmlPullParser in, String name, int defaultValue)1605 public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) { 1606 final String value = in.getAttributeValue(null, name); 1607 if (TextUtils.isEmpty(value)) { 1608 return defaultValue; 1609 } 1610 try { 1611 return Integer.parseInt(value); 1612 } catch (NumberFormatException e) { 1613 return defaultValue; 1614 } 1615 } 1616 readIntAttribute(XmlPullParser in, String name)1617 public static int readIntAttribute(XmlPullParser in, String name) throws IOException { 1618 final String value = in.getAttributeValue(null, name); 1619 try { 1620 return Integer.parseInt(value); 1621 } catch (NumberFormatException e) { 1622 throw new ProtocolException("problem parsing " + name + "=" + value + " as int"); 1623 } 1624 } 1625 writeIntAttribute(XmlSerializer out, String name, int value)1626 public static void writeIntAttribute(XmlSerializer out, String name, int value) 1627 throws IOException { 1628 out.attribute(null, name, Integer.toString(value)); 1629 } 1630 readLongAttribute(XmlPullParser in, String name, long defaultValue)1631 public static long readLongAttribute(XmlPullParser in, String name, long defaultValue) { 1632 final String value = in.getAttributeValue(null, name); 1633 if (TextUtils.isEmpty(value)) { 1634 return defaultValue; 1635 } 1636 try { 1637 return Long.parseLong(value); 1638 } catch (NumberFormatException e) { 1639 return defaultValue; 1640 } 1641 } 1642 readLongAttribute(XmlPullParser in, String name)1643 public static long readLongAttribute(XmlPullParser in, String name) throws IOException { 1644 final String value = in.getAttributeValue(null, name); 1645 try { 1646 return Long.parseLong(value); 1647 } catch (NumberFormatException e) { 1648 throw new ProtocolException("problem parsing " + name + "=" + value + " as long"); 1649 } 1650 } 1651 writeLongAttribute(XmlSerializer out, String name, long value)1652 public static void writeLongAttribute(XmlSerializer out, String name, long value) 1653 throws IOException { 1654 out.attribute(null, name, Long.toString(value)); 1655 } 1656 readFloatAttribute(XmlPullParser in, String name)1657 public static float readFloatAttribute(XmlPullParser in, String name) throws IOException { 1658 final String value = in.getAttributeValue(null, name); 1659 try { 1660 return Float.parseFloat(value); 1661 } catch (NumberFormatException e) { 1662 throw new ProtocolException("problem parsing " + name + "=" + value + " as long"); 1663 } 1664 } 1665 writeFloatAttribute(XmlSerializer out, String name, float value)1666 public static void writeFloatAttribute(XmlSerializer out, String name, float value) 1667 throws IOException { 1668 out.attribute(null, name, Float.toString(value)); 1669 } 1670 readBooleanAttribute(XmlPullParser in, String name)1671 public static boolean readBooleanAttribute(XmlPullParser in, String name) { 1672 final String value = in.getAttributeValue(null, name); 1673 return Boolean.parseBoolean(value); 1674 } 1675 readBooleanAttribute(XmlPullParser in, String name, boolean defaultValue)1676 public static boolean readBooleanAttribute(XmlPullParser in, String name, 1677 boolean defaultValue) { 1678 final String value = in.getAttributeValue(null, name); 1679 if (TextUtils.isEmpty(value)) { 1680 return defaultValue; 1681 } else { 1682 return Boolean.parseBoolean(value); 1683 } 1684 } 1685 writeBooleanAttribute(XmlSerializer out, String name, boolean value)1686 public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value) 1687 throws IOException { 1688 out.attribute(null, name, Boolean.toString(value)); 1689 } 1690 readUriAttribute(XmlPullParser in, String name)1691 public static Uri readUriAttribute(XmlPullParser in, String name) { 1692 final String value = in.getAttributeValue(null, name); 1693 return (value != null) ? Uri.parse(value) : null; 1694 } 1695 writeUriAttribute(XmlSerializer out, String name, Uri value)1696 public static void writeUriAttribute(XmlSerializer out, String name, Uri value) 1697 throws IOException { 1698 if (value != null) { 1699 out.attribute(null, name, value.toString()); 1700 } 1701 } 1702 readStringAttribute(XmlPullParser in, String name)1703 public static String readStringAttribute(XmlPullParser in, String name) { 1704 return in.getAttributeValue(null, name); 1705 } 1706 writeStringAttribute(XmlSerializer out, String name, CharSequence value)1707 public static void writeStringAttribute(XmlSerializer out, String name, CharSequence value) 1708 throws IOException { 1709 if (value != null) { 1710 out.attribute(null, name, value.toString()); 1711 } 1712 } 1713 readByteArrayAttribute(XmlPullParser in, String name)1714 public static byte[] readByteArrayAttribute(XmlPullParser in, String name) { 1715 final String value = in.getAttributeValue(null, name); 1716 if (!TextUtils.isEmpty(value)) { 1717 return Base64.decode(value, Base64.DEFAULT); 1718 } else { 1719 return null; 1720 } 1721 } 1722 writeByteArrayAttribute(XmlSerializer out, String name, byte[] value)1723 public static void writeByteArrayAttribute(XmlSerializer out, String name, byte[] value) 1724 throws IOException { 1725 if (value != null) { 1726 out.attribute(null, name, Base64.encodeToString(value, Base64.DEFAULT)); 1727 } 1728 } 1729 readBitmapAttribute(XmlPullParser in, String name)1730 public static Bitmap readBitmapAttribute(XmlPullParser in, String name) { 1731 final byte[] value = readByteArrayAttribute(in, name); 1732 if (value != null) { 1733 return BitmapFactory.decodeByteArray(value, 0, value.length); 1734 } else { 1735 return null; 1736 } 1737 } 1738 1739 @Deprecated writeBitmapAttribute(XmlSerializer out, String name, Bitmap value)1740 public static void writeBitmapAttribute(XmlSerializer out, String name, Bitmap value) 1741 throws IOException { 1742 if (value != null) { 1743 final ByteArrayOutputStream os = new ByteArrayOutputStream(); 1744 value.compress(CompressFormat.PNG, 90, os); 1745 writeByteArrayAttribute(out, name, os.toByteArray()); 1746 } 1747 } 1748 1749 /** @hide */ 1750 public interface WriteMapCallback { 1751 /** 1752 * Called from writeMapXml when an Object type is not recognized. The implementer 1753 * must write out the entire element including start and end tags. 1754 * 1755 * @param v The object to be written out 1756 * @param name The mapping key for v. Must be written into the "name" attribute of the 1757 * start tag. 1758 * @param out The XML output stream. 1759 * @throws XmlPullParserException on unrecognized Object type. 1760 * @throws IOException on XmlSerializer serialization errors. 1761 * @hide 1762 */ writeUnknownObject(Object v, String name, XmlSerializer out)1763 public void writeUnknownObject(Object v, String name, XmlSerializer out) 1764 throws XmlPullParserException, IOException; 1765 } 1766 1767 /** @hide */ 1768 public interface ReadMapCallback { 1769 /** 1770 * Called from readThisMapXml when a START_TAG is not recognized. The input stream 1771 * is positioned within the start tag so that attributes can be read using in.getAttribute. 1772 * 1773 * @param in the XML input stream 1774 * @param tag the START_TAG that was not recognized. 1775 * @return the Object parsed from the stream which will be put into the map. 1776 * @throws XmlPullParserException if the START_TAG is not recognized. 1777 * @throws IOException on XmlPullParser serialization errors. 1778 * @hide 1779 */ readThisUnknownObjectXml(XmlPullParser in, String tag)1780 public Object readThisUnknownObjectXml(XmlPullParser in, String tag) 1781 throws XmlPullParserException, IOException; 1782 } 1783 } 1784