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