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.compat.annotation.UnsupportedAppUsage; 20 import android.graphics.Bitmap; 21 import android.graphics.Bitmap.CompressFormat; 22 import android.graphics.BitmapFactory; 23 import android.net.Uri; 24 import android.text.TextUtils; 25 import android.util.ArrayMap; 26 import android.util.Base64; 27 import android.util.Xml; 28 29 import libcore.util.HexEncoding; 30 31 import org.xmlpull.v1.XmlPullParser; 32 import org.xmlpull.v1.XmlPullParserException; 33 import org.xmlpull.v1.XmlSerializer; 34 35 import java.io.ByteArrayOutputStream; 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.io.OutputStream; 39 import java.net.ProtocolException; 40 import java.nio.charset.StandardCharsets; 41 import java.util.ArrayList; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.Iterator; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.Set; 48 49 /** {@hide} */ 50 public class XmlUtils { 51 52 private static final String STRING_ARRAY_SEPARATOR = ":"; 53 54 @UnsupportedAppUsage skipCurrentTag(XmlPullParser parser)55 public static void skipCurrentTag(XmlPullParser parser) 56 throws XmlPullParserException, IOException { 57 int outerDepth = parser.getDepth(); 58 int type; 59 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 60 && (type != XmlPullParser.END_TAG 61 || parser.getDepth() > outerDepth)) { 62 } 63 } 64 65 public static final int convertValueToList(CharSequence value, String[] options, int defaultValue)66 convertValueToList(CharSequence value, String[] options, int defaultValue) 67 { 68 if (!TextUtils.isEmpty(value)) { 69 for (int i = 0; i < options.length; i++) { 70 if (value.equals(options[i])) 71 return i; 72 } 73 } 74 75 return defaultValue; 76 } 77 78 @UnsupportedAppUsage 79 public static final boolean convertValueToBoolean(CharSequence value, boolean defaultValue)80 convertValueToBoolean(CharSequence value, boolean defaultValue) 81 { 82 boolean result = false; 83 84 if (TextUtils.isEmpty(value)) { 85 return defaultValue; 86 } 87 88 if (value.equals("1") 89 || value.equals("true") 90 || value.equals("TRUE")) 91 result = true; 92 93 return result; 94 } 95 96 @UnsupportedAppUsage 97 public static final int convertValueToInt(CharSequence charSeq, int defaultValue)98 convertValueToInt(CharSequence charSeq, int defaultValue) 99 { 100 if (TextUtils.isEmpty(charSeq)) { 101 return defaultValue; 102 } 103 104 String nm = charSeq.toString(); 105 106 // XXX This code is copied from Integer.decode() so we don't 107 // have to instantiate an Integer! 108 109 int value; 110 int sign = 1; 111 int index = 0; 112 int len = nm.length(); 113 int base = 10; 114 115 if ('-' == nm.charAt(0)) { 116 sign = -1; 117 index++; 118 } 119 120 if ('0' == nm.charAt(index)) { 121 // Quick check for a zero by itself 122 if (index == (len - 1)) 123 return 0; 124 125 char c = nm.charAt(index + 1); 126 127 if ('x' == c || 'X' == c) { 128 index += 2; 129 base = 16; 130 } else { 131 index++; 132 base = 8; 133 } 134 } 135 else if ('#' == nm.charAt(index)) 136 { 137 index++; 138 base = 16; 139 } 140 141 return Integer.parseInt(nm.substring(index), base) * sign; 142 } 143 convertValueToUnsignedInt(String value, int defaultValue)144 public static int convertValueToUnsignedInt(String value, int defaultValue) { 145 if (TextUtils.isEmpty(value)) { 146 return defaultValue; 147 } 148 149 return parseUnsignedIntAttribute(value); 150 } 151 parseUnsignedIntAttribute(CharSequence charSeq)152 public static int parseUnsignedIntAttribute(CharSequence charSeq) { 153 String value = charSeq.toString(); 154 155 long bits; 156 int index = 0; 157 int len = value.length(); 158 int base = 10; 159 160 if ('0' == value.charAt(index)) { 161 // Quick check for zero by itself 162 if (index == (len - 1)) 163 return 0; 164 165 char c = value.charAt(index + 1); 166 167 if ('x' == c || 'X' == c) { // check for hex 168 index += 2; 169 base = 16; 170 } else { // check for octal 171 index++; 172 base = 8; 173 } 174 } else if ('#' == value.charAt(index)) { 175 index++; 176 base = 16; 177 } 178 179 return (int) Long.parseLong(value.substring(index), base); 180 } 181 182 /** 183 * Flatten a Map into an output stream as XML. The map can later be 184 * read back with readMapXml(). 185 * 186 * @param val The map to be flattened. 187 * @param out Where to write the XML data. 188 * 189 * @see #writeMapXml(Map, String, XmlSerializer) 190 * @see #writeListXml 191 * @see #writeValueXml 192 * @see #readMapXml 193 */ 194 @UnsupportedAppUsage writeMapXml(Map val, OutputStream out)195 public static final void writeMapXml(Map val, OutputStream out) 196 throws XmlPullParserException, java.io.IOException { 197 XmlSerializer serializer = new FastXmlSerializer(); 198 serializer.setOutput(out, StandardCharsets.UTF_8.name()); 199 serializer.startDocument(null, true); 200 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 201 writeMapXml(val, null, serializer); 202 serializer.endDocument(); 203 } 204 205 /** 206 * Flatten a List into an output stream as XML. The list can later be 207 * read back with readListXml(). 208 * 209 * @param val The list to be flattened. 210 * @param out Where to write the XML data. 211 * 212 * @see #writeListXml(List, String, XmlSerializer) 213 * @see #writeMapXml 214 * @see #writeValueXml 215 * @see #readListXml 216 */ writeListXml(List val, OutputStream out)217 public static final void writeListXml(List val, OutputStream out) 218 throws XmlPullParserException, java.io.IOException 219 { 220 XmlSerializer serializer = Xml.newSerializer(); 221 serializer.setOutput(out, StandardCharsets.UTF_8.name()); 222 serializer.startDocument(null, true); 223 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 224 writeListXml(val, null, serializer); 225 serializer.endDocument(); 226 } 227 228 /** 229 * Flatten a Map into an XmlSerializer. The map can later be read back 230 * with readThisMapXml(). 231 * 232 * @param val The map to be flattened. 233 * @param name Name attribute to include with this list's tag, or null for 234 * none. 235 * @param out XmlSerializer to write the map into. 236 * 237 * @see #writeMapXml(Map, OutputStream) 238 * @see #writeListXml 239 * @see #writeValueXml 240 * @see #readMapXml 241 */ writeMapXml(Map val, String name, XmlSerializer out)242 public static final void writeMapXml(Map val, String name, XmlSerializer out) 243 throws XmlPullParserException, java.io.IOException { 244 writeMapXml(val, name, out, null); 245 } 246 247 /** 248 * Flatten a Map into an XmlSerializer. The map can later be read back 249 * with readThisMapXml(). 250 * 251 * @param val The map to be flattened. 252 * @param name Name attribute to include with this list's tag, or null for 253 * none. 254 * @param out XmlSerializer to write the map into. 255 * @param callback Method to call when an Object type is not recognized. 256 * 257 * @see #writeMapXml(Map, OutputStream) 258 * @see #writeListXml 259 * @see #writeValueXml 260 * @see #readMapXml 261 * 262 * @hide 263 */ writeMapXml(Map val, String name, XmlSerializer out, WriteMapCallback callback)264 public static final void writeMapXml(Map val, String name, XmlSerializer out, 265 WriteMapCallback callback) throws XmlPullParserException, java.io.IOException { 266 267 if (val == null) { 268 out.startTag(null, "null"); 269 out.endTag(null, "null"); 270 return; 271 } 272 273 out.startTag(null, "map"); 274 if (name != null) { 275 out.attribute(null, "name", name); 276 } 277 278 writeMapXml(val, out, callback); 279 280 out.endTag(null, "map"); 281 } 282 283 /** 284 * Flatten a Map into an XmlSerializer. The map can later be read back 285 * with readThisMapXml(). This method presumes that the start tag and 286 * name attribute have already been written and does not write an end tag. 287 * 288 * @param val The map to be flattened. 289 * @param out XmlSerializer to write the map into. 290 * 291 * @see #writeMapXml(Map, OutputStream) 292 * @see #writeListXml 293 * @see #writeValueXml 294 * @see #readMapXml 295 * 296 * @hide 297 */ writeMapXml(Map val, XmlSerializer out, WriteMapCallback callback)298 public static final void writeMapXml(Map val, XmlSerializer out, 299 WriteMapCallback callback) throws XmlPullParserException, java.io.IOException { 300 if (val == null) { 301 return; 302 } 303 304 Set s = val.entrySet(); 305 Iterator i = s.iterator(); 306 307 while (i.hasNext()) { 308 Map.Entry e = (Map.Entry)i.next(); 309 writeValueXml(e.getValue(), (String)e.getKey(), out, callback); 310 } 311 } 312 313 /** 314 * Flatten a List into an XmlSerializer. The list can later be read back 315 * with readThisListXml(). 316 * 317 * @param val The list to be flattened. 318 * @param name Name attribute to include with this list's tag, or null for 319 * none. 320 * @param out XmlSerializer to write the list into. 321 * 322 * @see #writeListXml(List, OutputStream) 323 * @see #writeMapXml 324 * @see #writeValueXml 325 * @see #readListXml 326 */ writeListXml(List val, String name, XmlSerializer out)327 public static final void writeListXml(List val, String name, XmlSerializer out) 328 throws XmlPullParserException, java.io.IOException 329 { 330 if (val == null) { 331 out.startTag(null, "null"); 332 out.endTag(null, "null"); 333 return; 334 } 335 336 out.startTag(null, "list"); 337 if (name != null) { 338 out.attribute(null, "name", name); 339 } 340 341 int N = val.size(); 342 int i=0; 343 while (i < N) { 344 writeValueXml(val.get(i), null, out); 345 i++; 346 } 347 348 out.endTag(null, "list"); 349 } 350 writeSetXml(Set val, String name, XmlSerializer out)351 public static final void writeSetXml(Set val, String name, XmlSerializer out) 352 throws XmlPullParserException, java.io.IOException { 353 if (val == null) { 354 out.startTag(null, "null"); 355 out.endTag(null, "null"); 356 return; 357 } 358 359 out.startTag(null, "set"); 360 if (name != null) { 361 out.attribute(null, "name", name); 362 } 363 364 for (Object v : val) { 365 writeValueXml(v, null, out); 366 } 367 368 out.endTag(null, "set"); 369 } 370 371 /** 372 * Flatten a byte[] into an XmlSerializer. The list can later be read back 373 * with readThisByteArrayXml(). 374 * 375 * @param val The byte array to be flattened. 376 * @param name Name attribute to include with this array's tag, or null for 377 * none. 378 * @param out XmlSerializer to write the array into. 379 * 380 * @see #writeMapXml 381 * @see #writeValueXml 382 */ writeByteArrayXml(byte[] val, String name, XmlSerializer out)383 public static final void writeByteArrayXml(byte[] val, String name, 384 XmlSerializer out) 385 throws XmlPullParserException, java.io.IOException { 386 387 if (val == null) { 388 out.startTag(null, "null"); 389 out.endTag(null, "null"); 390 return; 391 } 392 393 out.startTag(null, "byte-array"); 394 if (name != null) { 395 out.attribute(null, "name", name); 396 } 397 398 final int N = val.length; 399 out.attribute(null, "num", Integer.toString(N)); 400 401 out.text(HexEncoding.encodeToString(val).toLowerCase()); 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") 735 @UnsupportedAppUsage readMapXml(InputStream in)736 public static final HashMap<String, ?> readMapXml(InputStream in) 737 throws XmlPullParserException, java.io.IOException 738 { 739 XmlPullParser parser = Xml.newPullParser(); 740 parser.setInput(in, StandardCharsets.UTF_8.name()); 741 return (HashMap<String, ?>) readValueXml(parser, new String[1]); 742 } 743 744 /** 745 * Read an ArrayList from an InputStream containing XML. The stream can 746 * previously have been written by writeListXml(). 747 * 748 * @param in The InputStream from which to read. 749 * 750 * @return ArrayList The resulting list. 751 * 752 * @see #readMapXml 753 * @see #readValueXml 754 * @see #readThisListXml 755 * @see #writeListXml 756 */ readListXml(InputStream in)757 public static final ArrayList readListXml(InputStream in) 758 throws XmlPullParserException, java.io.IOException 759 { 760 XmlPullParser parser = Xml.newPullParser(); 761 parser.setInput(in, StandardCharsets.UTF_8.name()); 762 return (ArrayList)readValueXml(parser, new String[1]); 763 } 764 765 766 /** 767 * Read a HashSet from an InputStream containing XML. The stream can 768 * previously have been written by writeSetXml(). 769 * 770 * @param in The InputStream from which to read. 771 * 772 * @return HashSet The resulting set. 773 * 774 * @throws XmlPullParserException 775 * @throws java.io.IOException 776 * 777 * @see #readValueXml 778 * @see #readThisSetXml 779 * @see #writeSetXml 780 */ readSetXml(InputStream in)781 public static final HashSet readSetXml(InputStream in) 782 throws XmlPullParserException, java.io.IOException { 783 XmlPullParser parser = Xml.newPullParser(); 784 parser.setInput(in, null); 785 return (HashSet) readValueXml(parser, new String[1]); 786 } 787 788 /** 789 * Read a HashMap object from an XmlPullParser. The XML data could 790 * previously have been generated by writeMapXml(). The XmlPullParser 791 * must be positioned <em>after</em> the tag that begins the map. 792 * 793 * @param parser The XmlPullParser from which to read the map data. 794 * @param endTag Name of the tag that will end the map, usually "map". 795 * @param name An array of one string, used to return the name attribute 796 * of the map's tag. 797 * 798 * @return HashMap The newly generated map. 799 * 800 * @see #readMapXml 801 */ readThisMapXml(XmlPullParser parser, String endTag, String[] name)802 public static final HashMap<String, ?> readThisMapXml(XmlPullParser parser, String endTag, 803 String[] name) throws XmlPullParserException, java.io.IOException { 804 return readThisMapXml(parser, endTag, name, null); 805 } 806 807 /** 808 * Read a HashMap object from an XmlPullParser. The XML data could 809 * previously have been generated by writeMapXml(). The XmlPullParser 810 * must be positioned <em>after</em> the tag that begins the map. 811 * 812 * @param parser The XmlPullParser from which to read the map data. 813 * @param endTag Name of the tag that will end the map, usually "map". 814 * @param name An array of one string, used to return the name attribute 815 * of the map's tag. 816 * 817 * @return HashMap The newly generated map. 818 * 819 * @see #readMapXml 820 * @hide 821 */ readThisMapXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback)822 public static final HashMap<String, ?> readThisMapXml(XmlPullParser parser, String endTag, 823 String[] name, ReadMapCallback callback) 824 throws XmlPullParserException, java.io.IOException 825 { 826 HashMap<String, Object> map = new HashMap<String, Object>(); 827 828 int eventType = parser.getEventType(); 829 do { 830 if (eventType == parser.START_TAG) { 831 Object val = readThisValueXml(parser, name, callback, false); 832 map.put(name[0], val); 833 } else if (eventType == parser.END_TAG) { 834 if (parser.getName().equals(endTag)) { 835 return map; 836 } 837 throw new XmlPullParserException( 838 "Expected " + endTag + " end tag at: " + parser.getName()); 839 } 840 eventType = parser.next(); 841 } while (eventType != parser.END_DOCUMENT); 842 843 throw new XmlPullParserException( 844 "Document ended before " + endTag + " end tag"); 845 } 846 847 /** 848 * Like {@link #readThisMapXml}, but returns an ArrayMap instead of HashMap. 849 * @hide 850 */ readThisArrayMapXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback)851 public static final ArrayMap<String, ?> readThisArrayMapXml(XmlPullParser parser, String endTag, 852 String[] name, ReadMapCallback callback) 853 throws XmlPullParserException, java.io.IOException 854 { 855 ArrayMap<String, Object> map = new ArrayMap<>(); 856 857 int eventType = parser.getEventType(); 858 do { 859 if (eventType == parser.START_TAG) { 860 Object val = readThisValueXml(parser, name, callback, true); 861 map.put(name[0], val); 862 } else if (eventType == parser.END_TAG) { 863 if (parser.getName().equals(endTag)) { 864 return map; 865 } 866 throw new XmlPullParserException( 867 "Expected " + endTag + " end tag at: " + parser.getName()); 868 } 869 eventType = parser.next(); 870 } while (eventType != parser.END_DOCUMENT); 871 872 throw new XmlPullParserException( 873 "Document ended before " + endTag + " end tag"); 874 } 875 876 /** 877 * Read an ArrayList object from an XmlPullParser. The XML data could 878 * previously have been generated by writeListXml(). The XmlPullParser 879 * must be positioned <em>after</em> the tag that begins the list. 880 * 881 * @param parser The XmlPullParser from which to read the list data. 882 * @param endTag Name of the tag that will end the list, usually "list". 883 * @param name An array of one string, used to return the name attribute 884 * of the list's tag. 885 * 886 * @return HashMap The newly generated list. 887 * 888 * @see #readListXml 889 */ readThisListXml(XmlPullParser parser, String endTag, String[] name)890 public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, 891 String[] name) throws XmlPullParserException, java.io.IOException { 892 return readThisListXml(parser, endTag, name, null, false); 893 } 894 895 /** 896 * Read an ArrayList object from an XmlPullParser. The XML data could 897 * previously have been generated by writeListXml(). The XmlPullParser 898 * must be positioned <em>after</em> the tag that begins the list. 899 * 900 * @param parser The XmlPullParser from which to read the list data. 901 * @param endTag Name of the tag that will end the list, usually "list". 902 * @param name An array of one string, used to return the name attribute 903 * of the list's tag. 904 * 905 * @return HashMap The newly generated list. 906 * 907 * @see #readListXml 908 */ readThisListXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback, boolean arrayMap)909 private static final ArrayList readThisListXml(XmlPullParser parser, String endTag, 910 String[] name, ReadMapCallback callback, boolean arrayMap) 911 throws XmlPullParserException, java.io.IOException { 912 ArrayList list = new ArrayList(); 913 914 int eventType = parser.getEventType(); 915 do { 916 if (eventType == parser.START_TAG) { 917 Object val = readThisValueXml(parser, name, callback, arrayMap); 918 list.add(val); 919 //System.out.println("Adding to list: " + val); 920 } else if (eventType == parser.END_TAG) { 921 if (parser.getName().equals(endTag)) { 922 return list; 923 } 924 throw new XmlPullParserException( 925 "Expected " + endTag + " end tag at: " + parser.getName()); 926 } 927 eventType = parser.next(); 928 } while (eventType != parser.END_DOCUMENT); 929 930 throw new XmlPullParserException( 931 "Document ended before " + endTag + " end tag"); 932 } 933 934 /** 935 * Read a HashSet object from an XmlPullParser. The XML data could previously 936 * have been generated by writeSetXml(). The XmlPullParser must be positioned 937 * <em>after</em> the tag that begins the set. 938 * 939 * @param parser The XmlPullParser from which to read the set data. 940 * @param endTag Name of the tag that will end the set, usually "set". 941 * @param name An array of one string, used to return the name attribute 942 * of the set's tag. 943 * 944 * @return HashSet The newly generated set. 945 * 946 * @throws XmlPullParserException 947 * @throws java.io.IOException 948 * 949 * @see #readSetXml 950 */ readThisSetXml(XmlPullParser parser, String endTag, String[] name)951 public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name) 952 throws XmlPullParserException, java.io.IOException { 953 return readThisSetXml(parser, endTag, name, null, false); 954 } 955 956 /** 957 * Read a HashSet object from an XmlPullParser. The XML data could previously 958 * have been generated by writeSetXml(). The XmlPullParser must be positioned 959 * <em>after</em> the tag that begins the set. 960 * 961 * @param parser The XmlPullParser from which to read the set data. 962 * @param endTag Name of the tag that will end the set, usually "set". 963 * @param name An array of one string, used to return the name attribute 964 * of the set's tag. 965 * 966 * @return HashSet The newly generated set. 967 * 968 * @throws XmlPullParserException 969 * @throws java.io.IOException 970 * 971 * @see #readSetXml 972 * @hide 973 */ readThisSetXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback, boolean arrayMap)974 private static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name, 975 ReadMapCallback callback, boolean arrayMap) 976 throws XmlPullParserException, java.io.IOException { 977 HashSet set = new HashSet(); 978 979 int eventType = parser.getEventType(); 980 do { 981 if (eventType == parser.START_TAG) { 982 Object val = readThisValueXml(parser, name, callback, arrayMap); 983 set.add(val); 984 //System.out.println("Adding to set: " + val); 985 } else if (eventType == parser.END_TAG) { 986 if (parser.getName().equals(endTag)) { 987 return set; 988 } 989 throw new XmlPullParserException( 990 "Expected " + endTag + " end tag at: " + parser.getName()); 991 } 992 eventType = parser.next(); 993 } while (eventType != parser.END_DOCUMENT); 994 995 throw new XmlPullParserException( 996 "Document ended before " + endTag + " end tag"); 997 } 998 999 /** 1000 * Read a byte[] object from an XmlPullParser. The XML data could 1001 * previously have been generated by writeByteArrayXml(). The XmlPullParser 1002 * must be positioned <em>after</em> the tag that begins the list. 1003 * 1004 * @param parser The XmlPullParser from which to read the list data. 1005 * @param endTag Name of the tag that will end the list, usually "list". 1006 * @param name An array of one string, used to return the name attribute 1007 * of the list's tag. 1008 * 1009 * @return Returns a newly generated byte[]. 1010 * 1011 * @see #writeByteArrayXml 1012 */ readThisByteArrayXml(XmlPullParser parser, String endTag, String[] name)1013 public static final byte[] readThisByteArrayXml(XmlPullParser parser, 1014 String endTag, String[] name) 1015 throws XmlPullParserException, java.io.IOException { 1016 1017 int num; 1018 try { 1019 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1020 } catch (NullPointerException e) { 1021 throw new XmlPullParserException( 1022 "Need num attribute in byte-array"); 1023 } catch (NumberFormatException e) { 1024 throw new XmlPullParserException( 1025 "Not a number in num attribute in byte-array"); 1026 } 1027 1028 // 0 len byte array does not have a text in the XML tag. So, initialize to 0 len array. 1029 // For all other array lens, HexEncoding.decode() below overrides the array. 1030 byte[] array = new byte[0]; 1031 1032 int eventType = parser.getEventType(); 1033 do { 1034 if (eventType == parser.TEXT) { 1035 if (num > 0) { 1036 String values = parser.getText(); 1037 if (values == null || values.length() != num * 2) { 1038 throw new XmlPullParserException( 1039 "Invalid value found in byte-array: " + values); 1040 } 1041 array = HexEncoding.decode(values); 1042 } 1043 } else if (eventType == parser.END_TAG) { 1044 if (parser.getName().equals(endTag)) { 1045 return array; 1046 } else { 1047 throw new XmlPullParserException( 1048 "Expected " + endTag + " end tag at: " 1049 + parser.getName()); 1050 } 1051 } 1052 eventType = parser.next(); 1053 } while (eventType != parser.END_DOCUMENT); 1054 1055 throw new XmlPullParserException( 1056 "Document ended before " + endTag + " end tag"); 1057 } 1058 1059 /** 1060 * Read an int[] object from an XmlPullParser. The XML data could 1061 * previously have been generated by writeIntArrayXml(). The XmlPullParser 1062 * must be positioned <em>after</em> the tag that begins the list. 1063 * 1064 * @param parser The XmlPullParser from which to read the list data. 1065 * @param endTag Name of the tag that will end the list, usually "list". 1066 * @param name An array of one string, used to return the name attribute 1067 * of the list's tag. 1068 * 1069 * @return Returns a newly generated int[]. 1070 * 1071 * @see #readListXml 1072 */ readThisIntArrayXml(XmlPullParser parser, String endTag, String[] name)1073 public static final int[] readThisIntArrayXml(XmlPullParser parser, 1074 String endTag, String[] name) 1075 throws XmlPullParserException, java.io.IOException { 1076 1077 int num; 1078 try { 1079 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1080 } catch (NullPointerException e) { 1081 throw new XmlPullParserException( 1082 "Need num attribute in int-array"); 1083 } catch (NumberFormatException e) { 1084 throw new XmlPullParserException( 1085 "Not a number in num attribute in int-array"); 1086 } 1087 parser.next(); 1088 1089 int[] array = new int[num]; 1090 int i = 0; 1091 1092 int eventType = parser.getEventType(); 1093 do { 1094 if (eventType == parser.START_TAG) { 1095 if (parser.getName().equals("item")) { 1096 try { 1097 array[i] = Integer.parseInt( 1098 parser.getAttributeValue(null, "value")); 1099 } catch (NullPointerException e) { 1100 throw new XmlPullParserException( 1101 "Need value attribute in item"); 1102 } catch (NumberFormatException e) { 1103 throw new XmlPullParserException( 1104 "Not a number in value attribute in item"); 1105 } 1106 } else { 1107 throw new XmlPullParserException( 1108 "Expected item tag at: " + parser.getName()); 1109 } 1110 } else if (eventType == parser.END_TAG) { 1111 if (parser.getName().equals(endTag)) { 1112 return array; 1113 } else if (parser.getName().equals("item")) { 1114 i++; 1115 } else { 1116 throw new XmlPullParserException( 1117 "Expected " + endTag + " end tag at: " 1118 + parser.getName()); 1119 } 1120 } 1121 eventType = parser.next(); 1122 } while (eventType != parser.END_DOCUMENT); 1123 1124 throw new XmlPullParserException( 1125 "Document ended before " + endTag + " end tag"); 1126 } 1127 1128 /** 1129 * Read a long[] object from an XmlPullParser. The XML data could 1130 * previously have been generated by writeLongArrayXml(). The XmlPullParser 1131 * must be positioned <em>after</em> the tag that begins the list. 1132 * 1133 * @param parser The XmlPullParser from which to read the list data. 1134 * @param endTag Name of the tag that will end the list, usually "list". 1135 * @param name An array of one string, used to return the name attribute 1136 * of the list's tag. 1137 * 1138 * @return Returns a newly generated long[]. 1139 * 1140 * @see #readListXml 1141 */ readThisLongArrayXml(XmlPullParser parser, String endTag, String[] name)1142 public static final long[] readThisLongArrayXml(XmlPullParser parser, 1143 String endTag, String[] name) 1144 throws XmlPullParserException, java.io.IOException { 1145 1146 int num; 1147 try { 1148 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1149 } catch (NullPointerException e) { 1150 throw new XmlPullParserException("Need num attribute in long-array"); 1151 } catch (NumberFormatException e) { 1152 throw new XmlPullParserException("Not a number in num attribute in long-array"); 1153 } 1154 parser.next(); 1155 1156 long[] array = new long[num]; 1157 int i = 0; 1158 1159 int eventType = parser.getEventType(); 1160 do { 1161 if (eventType == parser.START_TAG) { 1162 if (parser.getName().equals("item")) { 1163 try { 1164 array[i] = Long.parseLong(parser.getAttributeValue(null, "value")); 1165 } catch (NullPointerException e) { 1166 throw new XmlPullParserException("Need value attribute in item"); 1167 } catch (NumberFormatException e) { 1168 throw new XmlPullParserException("Not a number in value attribute in item"); 1169 } 1170 } else { 1171 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 1172 } 1173 } else if (eventType == parser.END_TAG) { 1174 if (parser.getName().equals(endTag)) { 1175 return array; 1176 } else if (parser.getName().equals("item")) { 1177 i++; 1178 } else { 1179 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + 1180 parser.getName()); 1181 } 1182 } 1183 eventType = parser.next(); 1184 } while (eventType != parser.END_DOCUMENT); 1185 1186 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 1187 } 1188 1189 /** 1190 * Read a double[] object from an XmlPullParser. The XML data could 1191 * previously have been generated by writeDoubleArrayXml(). The XmlPullParser 1192 * must be positioned <em>after</em> the tag that begins the list. 1193 * 1194 * @param parser The XmlPullParser from which to read the list data. 1195 * @param endTag Name of the tag that will end the list, usually "double-array". 1196 * @param name An array of one string, used to return the name attribute 1197 * of the list's tag. 1198 * 1199 * @return Returns a newly generated double[]. 1200 * 1201 * @see #readListXml 1202 */ readThisDoubleArrayXml(XmlPullParser parser, String endTag, String[] name)1203 public static final double[] readThisDoubleArrayXml(XmlPullParser parser, String endTag, 1204 String[] name) throws XmlPullParserException, java.io.IOException { 1205 1206 int num; 1207 try { 1208 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1209 } catch (NullPointerException e) { 1210 throw new XmlPullParserException("Need num attribute in double-array"); 1211 } catch (NumberFormatException e) { 1212 throw new XmlPullParserException("Not a number in num attribute in double-array"); 1213 } 1214 parser.next(); 1215 1216 double[] array = new double[num]; 1217 int i = 0; 1218 1219 int eventType = parser.getEventType(); 1220 do { 1221 if (eventType == parser.START_TAG) { 1222 if (parser.getName().equals("item")) { 1223 try { 1224 array[i] = Double.parseDouble(parser.getAttributeValue(null, "value")); 1225 } catch (NullPointerException e) { 1226 throw new XmlPullParserException("Need value attribute in item"); 1227 } catch (NumberFormatException e) { 1228 throw new XmlPullParserException("Not a number in value attribute in item"); 1229 } 1230 } else { 1231 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 1232 } 1233 } else if (eventType == parser.END_TAG) { 1234 if (parser.getName().equals(endTag)) { 1235 return array; 1236 } else if (parser.getName().equals("item")) { 1237 i++; 1238 } else { 1239 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + 1240 parser.getName()); 1241 } 1242 } 1243 eventType = parser.next(); 1244 } while (eventType != parser.END_DOCUMENT); 1245 1246 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 1247 } 1248 1249 /** 1250 * Read a String[] object from an XmlPullParser. The XML data could 1251 * previously have been generated by writeStringArrayXml(). The XmlPullParser 1252 * must be positioned <em>after</em> the tag that begins the list. 1253 * 1254 * @param parser The XmlPullParser from which to read the list data. 1255 * @param endTag Name of the tag that will end the list, usually "string-array". 1256 * @param name An array of one string, used to return the name attribute 1257 * of the list's tag. 1258 * 1259 * @return Returns a newly generated String[]. 1260 * 1261 * @see #readListXml 1262 */ readThisStringArrayXml(XmlPullParser parser, String endTag, String[] name)1263 public static final String[] readThisStringArrayXml(XmlPullParser parser, String endTag, 1264 String[] name) throws XmlPullParserException, java.io.IOException { 1265 1266 int num; 1267 try { 1268 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1269 } catch (NullPointerException e) { 1270 throw new XmlPullParserException("Need num attribute in string-array"); 1271 } catch (NumberFormatException e) { 1272 throw new XmlPullParserException("Not a number in num attribute in string-array"); 1273 } 1274 parser.next(); 1275 1276 String[] array = new String[num]; 1277 int i = 0; 1278 1279 int eventType = parser.getEventType(); 1280 do { 1281 if (eventType == parser.START_TAG) { 1282 if (parser.getName().equals("item")) { 1283 try { 1284 array[i] = parser.getAttributeValue(null, "value"); 1285 } catch (NullPointerException e) { 1286 throw new XmlPullParserException("Need value attribute in item"); 1287 } catch (NumberFormatException e) { 1288 throw new XmlPullParserException("Not a number in value attribute in item"); 1289 } 1290 } else { 1291 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 1292 } 1293 } else if (eventType == parser.END_TAG) { 1294 if (parser.getName().equals(endTag)) { 1295 return array; 1296 } else if (parser.getName().equals("item")) { 1297 i++; 1298 } else { 1299 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + 1300 parser.getName()); 1301 } 1302 } 1303 eventType = parser.next(); 1304 } while (eventType != parser.END_DOCUMENT); 1305 1306 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 1307 } 1308 1309 /** 1310 * Read a boolean[] object from an XmlPullParser. The XML data could 1311 * previously have been generated by writeBooleanArrayXml(). The XmlPullParser 1312 * must be positioned <em>after</em> the tag that begins the list. 1313 * 1314 * @param parser The XmlPullParser from which to read the list data. 1315 * @param endTag Name of the tag that will end the list, usually "string-array". 1316 * @param name An array of one string, used to return the name attribute 1317 * of the list's tag. 1318 * 1319 * @return Returns a newly generated boolean[]. 1320 * 1321 * @see #readListXml 1322 */ readThisBooleanArrayXml(XmlPullParser parser, String endTag, String[] name)1323 public static final boolean[] readThisBooleanArrayXml(XmlPullParser parser, String endTag, 1324 String[] name) throws XmlPullParserException, java.io.IOException { 1325 1326 int num; 1327 try { 1328 num = Integer.parseInt(parser.getAttributeValue(null, "num")); 1329 } catch (NullPointerException e) { 1330 throw new XmlPullParserException("Need num attribute in string-array"); 1331 } catch (NumberFormatException e) { 1332 throw new XmlPullParserException("Not a number in num attribute in string-array"); 1333 } 1334 parser.next(); 1335 1336 boolean[] array = new boolean[num]; 1337 int i = 0; 1338 1339 int eventType = parser.getEventType(); 1340 do { 1341 if (eventType == parser.START_TAG) { 1342 if (parser.getName().equals("item")) { 1343 try { 1344 array[i] = Boolean.parseBoolean(parser.getAttributeValue(null, "value")); 1345 } catch (NullPointerException e) { 1346 throw new XmlPullParserException("Need value attribute in item"); 1347 } catch (NumberFormatException e) { 1348 throw new XmlPullParserException("Not a number in value attribute in item"); 1349 } 1350 } else { 1351 throw new XmlPullParserException("Expected item tag at: " + parser.getName()); 1352 } 1353 } else if (eventType == parser.END_TAG) { 1354 if (parser.getName().equals(endTag)) { 1355 return array; 1356 } else if (parser.getName().equals("item")) { 1357 i++; 1358 } else { 1359 throw new XmlPullParserException("Expected " + endTag + " end tag at: " + 1360 parser.getName()); 1361 } 1362 } 1363 eventType = parser.next(); 1364 } while (eventType != parser.END_DOCUMENT); 1365 1366 throw new XmlPullParserException("Document ended before " + endTag + " end tag"); 1367 } 1368 1369 /** 1370 * Read a flattened object from an XmlPullParser. The XML data could 1371 * previously have been written with writeMapXml(), writeListXml(), or 1372 * writeValueXml(). The XmlPullParser must be positioned <em>at</em> the 1373 * tag that defines the value. 1374 * 1375 * @param parser The XmlPullParser from which to read the object. 1376 * @param name An array of one string, used to return the name attribute 1377 * of the value's tag. 1378 * 1379 * @return Object The newly generated value object. 1380 * 1381 * @see #readMapXml 1382 * @see #readListXml 1383 * @see #writeValueXml 1384 */ readValueXml(XmlPullParser parser, String[] name)1385 public static final Object readValueXml(XmlPullParser parser, String[] name) 1386 throws XmlPullParserException, java.io.IOException 1387 { 1388 int eventType = parser.getEventType(); 1389 do { 1390 if (eventType == parser.START_TAG) { 1391 return readThisValueXml(parser, name, null, false); 1392 } else if (eventType == parser.END_TAG) { 1393 throw new XmlPullParserException( 1394 "Unexpected end tag at: " + parser.getName()); 1395 } else if (eventType == parser.TEXT) { 1396 throw new XmlPullParserException( 1397 "Unexpected text: " + parser.getText()); 1398 } 1399 eventType = parser.next(); 1400 } while (eventType != parser.END_DOCUMENT); 1401 1402 throw new XmlPullParserException( 1403 "Unexpected end of document"); 1404 } 1405 readThisValueXml(XmlPullParser parser, String[] name, ReadMapCallback callback, boolean arrayMap)1406 private static final Object readThisValueXml(XmlPullParser parser, String[] name, 1407 ReadMapCallback callback, boolean arrayMap) 1408 throws XmlPullParserException, java.io.IOException { 1409 final String valueName = parser.getAttributeValue(null, "name"); 1410 final String tagName = parser.getName(); 1411 1412 //System.out.println("Reading this value tag: " + tagName + ", name=" + valueName); 1413 1414 Object res; 1415 1416 if (tagName.equals("null")) { 1417 res = null; 1418 } else if (tagName.equals("string")) { 1419 String value = ""; 1420 int eventType; 1421 while ((eventType = parser.next()) != parser.END_DOCUMENT) { 1422 if (eventType == parser.END_TAG) { 1423 if (parser.getName().equals("string")) { 1424 name[0] = valueName; 1425 //System.out.println("Returning value for " + valueName + ": " + value); 1426 return value; 1427 } 1428 throw new XmlPullParserException( 1429 "Unexpected end tag in <string>: " + parser.getName()); 1430 } else if (eventType == parser.TEXT) { 1431 value += parser.getText(); 1432 } else if (eventType == parser.START_TAG) { 1433 throw new XmlPullParserException( 1434 "Unexpected start tag in <string>: " + parser.getName()); 1435 } 1436 } 1437 throw new XmlPullParserException( 1438 "Unexpected end of document in <string>"); 1439 } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) { 1440 // all work already done by readThisPrimitiveValueXml 1441 } else if (tagName.equals("byte-array")) { 1442 res = readThisByteArrayXml(parser, "byte-array", name); 1443 name[0] = valueName; 1444 //System.out.println("Returning value for " + valueName + ": " + res); 1445 return res; 1446 } else if (tagName.equals("int-array")) { 1447 res = readThisIntArrayXml(parser, "int-array", name); 1448 name[0] = valueName; 1449 //System.out.println("Returning value for " + valueName + ": " + res); 1450 return res; 1451 } else if (tagName.equals("long-array")) { 1452 res = readThisLongArrayXml(parser, "long-array", name); 1453 name[0] = valueName; 1454 //System.out.println("Returning value for " + valueName + ": " + res); 1455 return res; 1456 } else if (tagName.equals("double-array")) { 1457 res = readThisDoubleArrayXml(parser, "double-array", name); 1458 name[0] = valueName; 1459 //System.out.println("Returning value for " + valueName + ": " + res); 1460 return res; 1461 } else if (tagName.equals("string-array")) { 1462 res = readThisStringArrayXml(parser, "string-array", name); 1463 name[0] = valueName; 1464 //System.out.println("Returning value for " + valueName + ": " + res); 1465 return res; 1466 } else if (tagName.equals("boolean-array")) { 1467 res = readThisBooleanArrayXml(parser, "boolean-array", name); 1468 name[0] = valueName; 1469 //System.out.println("Returning value for " + valueName + ": " + res); 1470 return res; 1471 } else if (tagName.equals("map")) { 1472 parser.next(); 1473 res = arrayMap 1474 ? readThisArrayMapXml(parser, "map", name, callback) 1475 : readThisMapXml(parser, "map", name, callback); 1476 name[0] = valueName; 1477 //System.out.println("Returning value for " + valueName + ": " + res); 1478 return res; 1479 } else if (tagName.equals("list")) { 1480 parser.next(); 1481 res = readThisListXml(parser, "list", name, callback, arrayMap); 1482 name[0] = valueName; 1483 //System.out.println("Returning value for " + valueName + ": " + res); 1484 return res; 1485 } else if (tagName.equals("set")) { 1486 parser.next(); 1487 res = readThisSetXml(parser, "set", name, callback, arrayMap); 1488 name[0] = valueName; 1489 //System.out.println("Returning value for " + valueName + ": " + res); 1490 return res; 1491 } else if (callback != null) { 1492 res = callback.readThisUnknownObjectXml(parser, tagName); 1493 name[0] = valueName; 1494 return res; 1495 } else { 1496 throw new XmlPullParserException("Unknown tag: " + tagName); 1497 } 1498 1499 // Skip through to end tag. 1500 int eventType; 1501 while ((eventType = parser.next()) != parser.END_DOCUMENT) { 1502 if (eventType == parser.END_TAG) { 1503 if (parser.getName().equals(tagName)) { 1504 name[0] = valueName; 1505 //System.out.println("Returning value for " + valueName + ": " + res); 1506 return res; 1507 } 1508 throw new XmlPullParserException( 1509 "Unexpected end tag in <" + tagName + ">: " + parser.getName()); 1510 } else if (eventType == parser.TEXT) { 1511 throw new XmlPullParserException( 1512 "Unexpected text in <" + tagName + ">: " + parser.getName()); 1513 } else if (eventType == parser.START_TAG) { 1514 throw new XmlPullParserException( 1515 "Unexpected start tag in <" + tagName + ">: " + parser.getName()); 1516 } 1517 } 1518 throw new XmlPullParserException( 1519 "Unexpected end of document in <" + tagName + ">"); 1520 } 1521 readThisPrimitiveValueXml(XmlPullParser parser, String tagName)1522 private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName) 1523 throws XmlPullParserException, java.io.IOException 1524 { 1525 try { 1526 if (tagName.equals("int")) { 1527 return Integer.parseInt(parser.getAttributeValue(null, "value")); 1528 } else if (tagName.equals("long")) { 1529 return Long.valueOf(parser.getAttributeValue(null, "value")); 1530 } else if (tagName.equals("float")) { 1531 return new Float(parser.getAttributeValue(null, "value")); 1532 } else if (tagName.equals("double")) { 1533 return new Double(parser.getAttributeValue(null, "value")); 1534 } else if (tagName.equals("boolean")) { 1535 return Boolean.valueOf(parser.getAttributeValue(null, "value")); 1536 } else { 1537 return null; 1538 } 1539 } catch (NullPointerException e) { 1540 throw new XmlPullParserException("Need value attribute in <" + tagName + ">"); 1541 } catch (NumberFormatException e) { 1542 throw new XmlPullParserException( 1543 "Not a number in value attribute in <" + tagName + ">"); 1544 } 1545 } 1546 1547 @UnsupportedAppUsage beginDocument(XmlPullParser parser, String firstElementName)1548 public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException 1549 { 1550 int type; 1551 while ((type=parser.next()) != parser.START_TAG 1552 && type != parser.END_DOCUMENT) { 1553 ; 1554 } 1555 1556 if (type != parser.START_TAG) { 1557 throw new XmlPullParserException("No start tag found"); 1558 } 1559 1560 if (!parser.getName().equals(firstElementName)) { 1561 throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() + 1562 ", expected " + firstElementName); 1563 } 1564 } 1565 1566 @UnsupportedAppUsage nextElement(XmlPullParser parser)1567 public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException 1568 { 1569 int type; 1570 while ((type=parser.next()) != parser.START_TAG 1571 && type != parser.END_DOCUMENT) { 1572 ; 1573 } 1574 } 1575 nextElementWithin(XmlPullParser parser, int outerDepth)1576 public static boolean nextElementWithin(XmlPullParser parser, int outerDepth) 1577 throws IOException, XmlPullParserException { 1578 for (;;) { 1579 int type = parser.next(); 1580 if (type == XmlPullParser.END_DOCUMENT 1581 || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) { 1582 return false; 1583 } 1584 if (type == XmlPullParser.START_TAG 1585 && parser.getDepth() == outerDepth + 1) { 1586 return true; 1587 } 1588 } 1589 } 1590 readIntAttribute(XmlPullParser in, String name, int defaultValue)1591 public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) { 1592 final String value = in.getAttributeValue(null, name); 1593 if (TextUtils.isEmpty(value)) { 1594 return defaultValue; 1595 } 1596 try { 1597 return Integer.parseInt(value); 1598 } catch (NumberFormatException e) { 1599 return defaultValue; 1600 } 1601 } 1602 readIntAttribute(XmlPullParser in, String name)1603 public static int readIntAttribute(XmlPullParser in, String name) throws IOException { 1604 final String value = in.getAttributeValue(null, name); 1605 try { 1606 return Integer.parseInt(value); 1607 } catch (NumberFormatException e) { 1608 throw new ProtocolException("problem parsing " + name + "=" + value + " as int"); 1609 } 1610 } 1611 writeIntAttribute(XmlSerializer out, String name, int value)1612 public static void writeIntAttribute(XmlSerializer out, String name, int value) 1613 throws IOException { 1614 out.attribute(null, name, Integer.toString(value)); 1615 } 1616 readLongAttribute(XmlPullParser in, String name, long defaultValue)1617 public static long readLongAttribute(XmlPullParser in, String name, long defaultValue) { 1618 final String value = in.getAttributeValue(null, name); 1619 if (TextUtils.isEmpty(value)) { 1620 return defaultValue; 1621 } 1622 try { 1623 return Long.parseLong(value); 1624 } catch (NumberFormatException e) { 1625 return defaultValue; 1626 } 1627 } 1628 readLongAttribute(XmlPullParser in, String name)1629 public static long readLongAttribute(XmlPullParser in, String name) throws IOException { 1630 final String value = in.getAttributeValue(null, name); 1631 try { 1632 return Long.parseLong(value); 1633 } catch (NumberFormatException e) { 1634 throw new ProtocolException("problem parsing " + name + "=" + value + " as long"); 1635 } 1636 } 1637 writeLongAttribute(XmlSerializer out, String name, long value)1638 public static void writeLongAttribute(XmlSerializer out, String name, long value) 1639 throws IOException { 1640 out.attribute(null, name, Long.toString(value)); 1641 } 1642 readFloatAttribute(XmlPullParser in, String name)1643 public static float readFloatAttribute(XmlPullParser in, String name) throws IOException { 1644 final String value = in.getAttributeValue(null, name); 1645 try { 1646 return Float.parseFloat(value); 1647 } catch (NumberFormatException e) { 1648 throw new ProtocolException("problem parsing " + name + "=" + value + " as long"); 1649 } 1650 } 1651 writeFloatAttribute(XmlSerializer out, String name, float value)1652 public static void writeFloatAttribute(XmlSerializer out, String name, float value) 1653 throws IOException { 1654 out.attribute(null, name, Float.toString(value)); 1655 } 1656 readBooleanAttribute(XmlPullParser in, String name)1657 public static boolean readBooleanAttribute(XmlPullParser in, String name) { 1658 final String value = in.getAttributeValue(null, name); 1659 return Boolean.parseBoolean(value); 1660 } 1661 readBooleanAttribute(XmlPullParser in, String name, boolean defaultValue)1662 public static boolean readBooleanAttribute(XmlPullParser in, String name, 1663 boolean defaultValue) { 1664 final String value = in.getAttributeValue(null, name); 1665 if (TextUtils.isEmpty(value)) { 1666 return defaultValue; 1667 } else { 1668 return Boolean.parseBoolean(value); 1669 } 1670 } 1671 writeBooleanAttribute(XmlSerializer out, String name, boolean value)1672 public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value) 1673 throws IOException { 1674 out.attribute(null, name, Boolean.toString(value)); 1675 } 1676 readUriAttribute(XmlPullParser in, String name)1677 public static Uri readUriAttribute(XmlPullParser in, String name) { 1678 final String value = in.getAttributeValue(null, name); 1679 return (value != null) ? Uri.parse(value) : null; 1680 } 1681 writeUriAttribute(XmlSerializer out, String name, Uri value)1682 public static void writeUriAttribute(XmlSerializer out, String name, Uri value) 1683 throws IOException { 1684 if (value != null) { 1685 out.attribute(null, name, value.toString()); 1686 } 1687 } 1688 readStringAttribute(XmlPullParser in, String name)1689 public static String readStringAttribute(XmlPullParser in, String name) { 1690 return in.getAttributeValue(null, name); 1691 } 1692 writeStringAttribute(XmlSerializer out, String name, CharSequence value)1693 public static void writeStringAttribute(XmlSerializer out, String name, CharSequence value) 1694 throws IOException { 1695 if (value != null) { 1696 out.attribute(null, name, value.toString()); 1697 } 1698 } 1699 readByteArrayAttribute(XmlPullParser in, String name)1700 public static byte[] readByteArrayAttribute(XmlPullParser in, String name) { 1701 final String value = in.getAttributeValue(null, name); 1702 if (!TextUtils.isEmpty(value)) { 1703 return Base64.decode(value, Base64.DEFAULT); 1704 } else { 1705 return null; 1706 } 1707 } 1708 writeByteArrayAttribute(XmlSerializer out, String name, byte[] value)1709 public static void writeByteArrayAttribute(XmlSerializer out, String name, byte[] value) 1710 throws IOException { 1711 if (value != null) { 1712 out.attribute(null, name, Base64.encodeToString(value, Base64.DEFAULT)); 1713 } 1714 } 1715 readBitmapAttribute(XmlPullParser in, String name)1716 public static Bitmap readBitmapAttribute(XmlPullParser in, String name) { 1717 final byte[] value = readByteArrayAttribute(in, name); 1718 if (value != null) { 1719 return BitmapFactory.decodeByteArray(value, 0, value.length); 1720 } else { 1721 return null; 1722 } 1723 } 1724 1725 @Deprecated writeBitmapAttribute(XmlSerializer out, String name, Bitmap value)1726 public static void writeBitmapAttribute(XmlSerializer out, String name, Bitmap value) 1727 throws IOException { 1728 if (value != null) { 1729 final ByteArrayOutputStream os = new ByteArrayOutputStream(); 1730 value.compress(CompressFormat.PNG, 90, os); 1731 writeByteArrayAttribute(out, name, os.toByteArray()); 1732 } 1733 } 1734 1735 /** @hide */ 1736 public interface WriteMapCallback { 1737 /** 1738 * Called from writeMapXml when an Object type is not recognized. The implementer 1739 * must write out the entire element including start and end tags. 1740 * 1741 * @param v The object to be written out 1742 * @param name The mapping key for v. Must be written into the "name" attribute of the 1743 * start tag. 1744 * @param out The XML output stream. 1745 * @throws XmlPullParserException on unrecognized Object type. 1746 * @throws IOException on XmlSerializer serialization errors. 1747 * @hide 1748 */ writeUnknownObject(Object v, String name, XmlSerializer out)1749 public void writeUnknownObject(Object v, String name, XmlSerializer out) 1750 throws XmlPullParserException, IOException; 1751 } 1752 1753 /** @hide */ 1754 public interface ReadMapCallback { 1755 /** 1756 * Called from readThisMapXml when a START_TAG is not recognized. The input stream 1757 * is positioned within the start tag so that attributes can be read using in.getAttribute. 1758 * 1759 * @param in the XML input stream 1760 * @param tag the START_TAG that was not recognized. 1761 * @return the Object parsed from the stream which will be put into the map. 1762 * @throws XmlPullParserException if the START_TAG is not recognized. 1763 * @throws IOException on XmlPullParser serialization errors. 1764 * @hide 1765 */ readThisUnknownObjectXml(XmlPullParser in, String tag)1766 public Object readThisUnknownObjectXml(XmlPullParser in, String tag) 1767 throws XmlPullParserException, IOException; 1768 } 1769 } 1770