1 /* 2 * Copyright (C) 2023 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 android.app.appsearch.safeparcel; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.PendingIntent; 22 import android.os.Bundle; 23 import android.os.IBinder; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.util.SparseArray; 27 import android.util.SparseBooleanArray; 28 import android.util.SparseIntArray; 29 import android.util.SparseLongArray; 30 31 import java.math.BigDecimal; 32 import java.math.BigInteger; 33 import java.util.ArrayList; 34 import java.util.List; 35 36 /** 37 * Functions to read in a safe parcel. 38 * 39 * @hide 40 */ 41 // Include the SafeParcel source code directly in AppSearch until it gets officially open-sourced. 42 public class SafeParcelReader { 43 /** class to parse the exception. */ 44 public static class ParseException extends RuntimeException { ParseException(@onNull String message, @NonNull Parcel p)45 public ParseException(@NonNull String message, @NonNull Parcel p) { 46 super(message + " Parcel: pos=" + p.dataPosition() + " size=" + p.dataSize()); 47 } 48 } 49 SafeParcelReader()50 private SafeParcelReader() {} 51 52 /** Reads the header. */ readHeader(@onNull Parcel p)53 public static int readHeader(@NonNull Parcel p) { 54 return p.readInt(); 55 } 56 57 /** Gets the id for the field. */ getFieldId(int header)58 public static int getFieldId(int header) { 59 return header & 0x0000ffff; 60 } 61 62 /** Reads the size. */ readSize(@onNull Parcel p, int header)63 public static int readSize(@NonNull Parcel p, int header) { 64 if ((header & 0xffff0000) != 0xffff0000) { 65 return (header >> 16) & 0x0000ffff; 66 } else { 67 return p.readInt(); 68 } 69 } 70 71 /** Skips the unknown field. */ skipUnknownField(@onNull Parcel p, int header)72 public static void skipUnknownField(@NonNull Parcel p, int header) { 73 int size = readSize(p, header); 74 p.setDataPosition(p.dataPosition() + size); 75 } 76 readAndEnforceSize(@onNull Parcel p, int header, int required)77 private static void readAndEnforceSize(@NonNull Parcel p, int header, int required) { 78 final int size = readSize(p, header); 79 if (size != required) { 80 throw new ParseException( 81 "Expected size " 82 + required 83 + " got " 84 + size 85 + " (0x" 86 + Integer.toHexString(size) 87 + ")", 88 p); 89 } 90 } 91 enforceSize(@onNull Parcel p, int header, int size, int required)92 private static void enforceSize(@NonNull Parcel p, int header, int size, int required) { 93 if (size != required) { 94 throw new ParseException( 95 "Expected size " 96 + required 97 + " got " 98 + size 99 + " (0x" 100 + Integer.toHexString(size) 101 + ")", 102 p); 103 } 104 } 105 106 /** Returns the end position of the object in the parcel. */ validateObjectHeader(@onNull Parcel p)107 public static int validateObjectHeader(@NonNull Parcel p) { 108 final int header = readHeader(p); 109 final int size = readSize(p, header); 110 final int start = p.dataPosition(); 111 if (getFieldId(header) != SafeParcelWriter.OBJECT_HEADER) { 112 throw new ParseException( 113 "Expected object header. Got 0x" + Integer.toHexString(header), p); 114 } 115 final int end = start + size; 116 if (end < start || end > p.dataSize()) { 117 throw new ParseException("Size read is invalid start=" + start + " end=" + end, p); 118 } 119 return end; 120 } 121 122 /** Reads a boolean. */ readBoolean(@onNull Parcel p, int header)123 public static boolean readBoolean(@NonNull Parcel p, int header) { 124 readAndEnforceSize(p, header, 4); 125 return p.readInt() != 0; 126 } 127 128 /** Reads a {@link Boolean} object. */ 129 @Nullable readBooleanObject(@onNull Parcel p, int header)130 public static Boolean readBooleanObject(@NonNull Parcel p, int header) { 131 final int size = readSize(p, header); 132 if (size == 0) { 133 return null; 134 } else { 135 enforceSize(p, header, size, 4); 136 return p.readInt() != 0; 137 } 138 } 139 140 /** Reads a byte. */ readByte(@onNull Parcel p, int header)141 public static byte readByte(@NonNull Parcel p, int header) { 142 readAndEnforceSize(p, header, 4); 143 return (byte) p.readInt(); 144 } 145 146 /** Reads a char. */ readChar(@onNull Parcel p, int header)147 public static char readChar(@NonNull Parcel p, int header) { 148 readAndEnforceSize(p, header, 4); 149 return (char) p.readInt(); 150 } 151 152 /** Reads a short. */ readShort(@onNull Parcel p, int header)153 public static short readShort(@NonNull Parcel p, int header) { 154 readAndEnforceSize(p, header, 4); 155 return (short) p.readInt(); 156 } 157 158 /** Reads an int. */ readInt(@onNull Parcel p, int header)159 public static int readInt(@NonNull Parcel p, int header) { 160 readAndEnforceSize(p, header, 4); 161 return p.readInt(); 162 } 163 164 /** Reads an {@link Integer} object. */ 165 @Nullable readIntegerObject(@onNull Parcel p, int header)166 public static Integer readIntegerObject(@NonNull Parcel p, int header) { 167 final int size = readSize(p, header); 168 if (size == 0) { 169 return null; 170 } else { 171 enforceSize(p, header, size, 4); 172 return p.readInt(); 173 } 174 } 175 176 /** Reads a long. */ readLong(@onNull Parcel p, int header)177 public static long readLong(@NonNull Parcel p, int header) { 178 readAndEnforceSize(p, header, 8); 179 return p.readLong(); 180 } 181 182 /** Reads a {@link Long} object. */ 183 @Nullable readLongObject(@onNull Parcel p, int header)184 public static Long readLongObject(@NonNull Parcel p, int header) { 185 final int size = readSize(p, header); 186 if (size == 0) { 187 return null; 188 } else { 189 enforceSize(p, header, size, 8); 190 return p.readLong(); 191 } 192 } 193 194 /** Creates a {@link BigInteger}. */ 195 @Nullable createBigInteger(@onNull Parcel p, int header)196 public static BigInteger createBigInteger(@NonNull Parcel p, int header) { 197 final int size = readSize(p, header); 198 final int pos = p.dataPosition(); 199 if (size == 0) { 200 return null; 201 } 202 final byte[] val = p.createByteArray(); 203 p.setDataPosition(pos + size); 204 return new BigInteger(val); 205 } 206 207 /** Reads a float. */ readFloat(@onNull Parcel p, int header)208 public static float readFloat(@NonNull Parcel p, int header) { 209 readAndEnforceSize(p, header, 4); 210 return p.readFloat(); 211 } 212 213 /** Reads a {@link Float}. */ 214 @Nullable readFloatObject(@onNull Parcel p, int header)215 public static Float readFloatObject(@NonNull Parcel p, int header) { 216 final int size = readSize(p, header); 217 if (size == 0) { 218 return null; 219 } else { 220 enforceSize(p, header, size, 4); 221 return p.readFloat(); 222 } 223 } 224 225 /** Reads a double. */ readDouble(@onNull Parcel p, int header)226 public static double readDouble(@NonNull Parcel p, int header) { 227 readAndEnforceSize(p, header, 8); 228 return p.readDouble(); 229 } 230 231 /** Reads a {@link Double}. */ 232 @Nullable readDoubleObject(@onNull Parcel p, int header)233 public static Double readDoubleObject(@NonNull Parcel p, int header) { 234 final int size = readSize(p, header); 235 if (size == 0) { 236 return null; 237 } else { 238 enforceSize(p, header, size, 8); 239 return p.readDouble(); 240 } 241 } 242 243 /** Creates a {@link BigDecimal}. */ 244 @Nullable createBigDecimal(@onNull Parcel p, int header)245 public static BigDecimal createBigDecimal(@NonNull Parcel p, int header) { 246 final int size = readSize(p, header); 247 final int pos = p.dataPosition(); 248 if (size == 0) { 249 return null; 250 } 251 final byte[] unscaledValue = p.createByteArray(); 252 final int scale = p.readInt(); 253 p.setDataPosition(pos + size); 254 return new BigDecimal(new BigInteger(unscaledValue), scale); 255 } 256 257 /** Creates a {@link String}. */ 258 @Nullable createString(@onNull Parcel p, int header)259 public static String createString(@NonNull Parcel p, int header) { 260 final int size = readSize(p, header); 261 final int pos = p.dataPosition(); 262 if (size == 0) { 263 return null; 264 } 265 final String result = p.readString(); 266 p.setDataPosition(pos + size); 267 return result; 268 } 269 270 /** Reads an {@link IBinder}. */ 271 @Nullable readIBinder(@onNull Parcel p, int header)272 public static IBinder readIBinder(@NonNull Parcel p, int header) { 273 final int size = readSize(p, header); 274 final int pos = p.dataPosition(); 275 if (size == 0) { 276 return null; 277 } 278 final IBinder result = p.readStrongBinder(); 279 p.setDataPosition(pos + size); 280 return result; 281 } 282 283 /** Reads a {@link PendingIntent}. */ 284 @Nullable readPendingIntent(@onNull Parcel p, int header)285 public static PendingIntent readPendingIntent(@NonNull Parcel p, int header) { 286 final int size = readSize(p, header); 287 final int pos = p.dataPosition(); 288 if (size == 0) { 289 return null; 290 } 291 final PendingIntent result = PendingIntent.readPendingIntentOrNullFromParcel(p); 292 p.setDataPosition(pos + size); 293 return result; 294 } 295 296 /** Creates a {@link Parcelable}. */ 297 @Nullable createParcelable( @onNull Parcel p, int header, @NonNull Parcelable.Creator<T> creator)298 public static <T extends Parcelable> T createParcelable( 299 @NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> creator) { 300 final int size = readSize(p, header); 301 final int pos = p.dataPosition(); 302 if (size == 0) { 303 return null; 304 } 305 final T result = creator.createFromParcel(p); 306 p.setDataPosition(pos + size); 307 return result; 308 } 309 310 /** Creates a {@link Bundle}. */ 311 @Nullable createBundle(@onNull Parcel p, int header)312 public static Bundle createBundle(@NonNull Parcel p, int header) { 313 final int size = readSize(p, header); 314 final int pos = p.dataPosition(); 315 if (size == 0) { 316 return null; 317 } 318 final Bundle result = p.readBundle(); 319 p.setDataPosition(pos + size); 320 return result; 321 } 322 323 /** Creates a byte array. */ 324 @Nullable createByteArray(@onNull Parcel p, int header)325 public static byte[] createByteArray(@NonNull Parcel p, int header) { 326 final int size = readSize(p, header); 327 final int pos = p.dataPosition(); 328 if (size == 0) { 329 return null; 330 } 331 final byte[] result = p.createByteArray(); 332 p.setDataPosition(pos + size); 333 return result; 334 } 335 336 /** Creates a byte array array. */ 337 @Nullable createByteArrayArray(@onNull Parcel p, int header)338 public static byte[][] createByteArrayArray(@NonNull Parcel p, int header) { 339 final int size = readSize(p, header); 340 final int pos = p.dataPosition(); 341 if (size == 0) { 342 return null; 343 } 344 final int length = p.readInt(); 345 final byte[][] result = new byte[length][]; 346 for (int i = 0; i < length; i++) { 347 result[i] = p.createByteArray(); 348 } 349 p.setDataPosition(pos + size); 350 return result; 351 } 352 353 /** Creates a boolean array array. */ 354 @Nullable createBooleanArray(@onNull Parcel p, int header)355 public static boolean[] createBooleanArray(@NonNull Parcel p, int header) { 356 final int size = readSize(p, header); 357 final int pos = p.dataPosition(); 358 if (size == 0) { 359 return null; 360 } 361 final boolean[] result = p.createBooleanArray(); 362 p.setDataPosition(pos + size); 363 return result; 364 } 365 366 /** Creates a char array. */ 367 @Nullable createCharArray(@onNull Parcel p, int header)368 public static char[] createCharArray(@NonNull Parcel p, int header) { 369 final int size = readSize(p, header); 370 final int pos = p.dataPosition(); 371 if (size == 0) { 372 return null; 373 } 374 final char[] result = p.createCharArray(); 375 p.setDataPosition(pos + size); 376 return result; 377 } 378 379 /** Creates an int array. */ 380 @Nullable createIntArray(@onNull Parcel p, int header)381 public static int[] createIntArray(@NonNull Parcel p, int header) { 382 final int size = readSize(p, header); 383 final int pos = p.dataPosition(); 384 if (size == 0) { 385 return null; 386 } 387 final int[] result = p.createIntArray(); 388 p.setDataPosition(pos + size); 389 return result; 390 } 391 392 /** Creates a long array. */ 393 @Nullable createLongArray(@onNull Parcel p, int header)394 public static long[] createLongArray(@NonNull Parcel p, int header) { 395 final int size = readSize(p, header); 396 final int pos = p.dataPosition(); 397 if (size == 0) { 398 return null; 399 } 400 final long[] result = p.createLongArray(); 401 p.setDataPosition(pos + size); 402 return result; 403 } 404 405 /** Creates a {@link BigInteger} array. */ 406 @Nullable createBigIntegerArray(@onNull Parcel p, int header)407 public static BigInteger[] createBigIntegerArray(@NonNull Parcel p, int header) { 408 final int size = readSize(p, header); 409 final int pos = p.dataPosition(); 410 if (size == 0) { 411 return null; 412 } 413 final int length = p.readInt(); 414 final BigInteger[] result = new BigInteger[length]; 415 for (int i = 0; i < length; i++) { 416 result[i] = new BigInteger(p.createByteArray()); 417 } 418 p.setDataPosition(pos + size); 419 return result; 420 } 421 422 /** Creates a float array. */ 423 @Nullable createFloatArray(@onNull Parcel p, int header)424 public static float[] createFloatArray(@NonNull Parcel p, int header) { 425 final int size = readSize(p, header); 426 final int pos = p.dataPosition(); 427 if (size == 0) { 428 return null; 429 } 430 final float[] result = p.createFloatArray(); 431 p.setDataPosition(pos + size); 432 return result; 433 } 434 435 /** Creates a double array. */ 436 @Nullable createDoubleArray(@onNull Parcel p, int header)437 public static double[] createDoubleArray(@NonNull Parcel p, int header) { 438 final int size = readSize(p, header); 439 final int pos = p.dataPosition(); 440 if (size == 0) { 441 return null; 442 } 443 final double[] result = p.createDoubleArray(); 444 p.setDataPosition(pos + size); 445 return result; 446 } 447 448 /** Creates a {@link BigDecimal} array. */ 449 @Nullable createBigDecimalArray(@onNull Parcel p, int header)450 public static BigDecimal[] createBigDecimalArray(@NonNull Parcel p, int header) { 451 final int size = readSize(p, header); 452 final int pos = p.dataPosition(); 453 if (size == 0) { 454 return null; 455 } 456 final int length = p.readInt(); 457 final BigDecimal[] result = new BigDecimal[length]; 458 for (int i = 0; i < length; i++) { 459 byte[] unscaledValue = p.createByteArray(); 460 int scale = p.readInt(); 461 result[i] = new BigDecimal(new BigInteger(unscaledValue), scale); 462 } 463 p.setDataPosition(pos + size); 464 return result; 465 } 466 467 /** Creates a {@link String} array. */ 468 @Nullable createStringArray(@onNull Parcel p, int header)469 public static String[] createStringArray(@NonNull Parcel p, int header) { 470 final int size = readSize(p, header); 471 final int pos = p.dataPosition(); 472 if (size == 0) { 473 return null; 474 } 475 final String[] result = p.createStringArray(); 476 p.setDataPosition(pos + size); 477 return result; 478 } 479 480 /** Creates a {@link IBinder} array. */ 481 @Nullable createIBinderArray(@onNull Parcel p, int header)482 public static IBinder[] createIBinderArray(@NonNull Parcel p, int header) { 483 final int size = readSize(p, header); 484 final int pos = p.dataPosition(); 485 if (size == 0) { 486 return null; 487 } 488 final IBinder[] result = p.createBinderArray(); 489 p.setDataPosition(pos + size); 490 return result; 491 } 492 493 /** Creates a {@link Boolean} list. */ 494 @Nullable createBooleanList(@onNull Parcel p, int header)495 public static ArrayList<Boolean> createBooleanList(@NonNull Parcel p, int header) { 496 final int size = readSize(p, header); 497 final int pos = p.dataPosition(); 498 if (size == 0) { 499 return null; 500 } 501 final ArrayList<Boolean> result = new ArrayList<Boolean>(); 502 final int count = p.readInt(); 503 for (int i = 0; i < count; i++) { 504 result.add(p.readInt() != 0 ? true : false); 505 } 506 p.setDataPosition(pos + size); 507 return result; 508 } 509 510 /** Creates a {@link Integer} list. */ 511 @Nullable createIntegerList(@onNull Parcel p, int header)512 public static ArrayList<Integer> createIntegerList(@NonNull Parcel p, int header) { 513 final int size = readSize(p, header); 514 final int pos = p.dataPosition(); 515 if (size == 0) { 516 return null; 517 } 518 final ArrayList<Integer> result = new ArrayList<Integer>(); 519 final int count = p.readInt(); 520 for (int i = 0; i < count; i++) { 521 result.add(p.readInt()); 522 } 523 p.setDataPosition(pos + size); 524 return result; 525 } 526 527 /** Creates a {@link SparseBooleanArray}. */ 528 @Nullable createSparseBooleanArray(@onNull Parcel p, int header)529 public static SparseBooleanArray createSparseBooleanArray(@NonNull Parcel p, int header) { 530 final int size = readSize(p, header); 531 final int pos = p.dataPosition(); 532 if (size == 0) { 533 return null; 534 } 535 SparseBooleanArray result = p.readSparseBooleanArray(); 536 p.setDataPosition(pos + size); 537 return result; 538 } 539 540 /** Creates a {@link SparseIntArray}. */ 541 @Nullable createSparseIntArray(@onNull Parcel p, int header)542 public static SparseIntArray createSparseIntArray(@NonNull Parcel p, int header) { 543 final int size = readSize(p, header); 544 final int pos = p.dataPosition(); 545 if (size == 0) { 546 return null; 547 } 548 final SparseIntArray result = new SparseIntArray(); 549 final int count = p.readInt(); 550 for (int i = 0; i < count; i++) { 551 int key = p.readInt(); 552 int value = p.readInt(); 553 result.append(key, value); 554 } 555 p.setDataPosition(pos + size); 556 return result; 557 } 558 559 /** Creates a {@link Float} {@link SparseArray}. */ 560 @Nullable createFloatSparseArray(@onNull Parcel p, int header)561 public static SparseArray<Float> createFloatSparseArray(@NonNull Parcel p, int header) { 562 final int size = readSize(p, header); 563 final int pos = p.dataPosition(); 564 if (size == 0) { 565 return null; 566 } 567 final SparseArray<Float> result = new SparseArray<Float>(); 568 final int count = p.readInt(); 569 for (int i = 0; i < count; i++) { 570 int key = p.readInt(); 571 float value = p.readFloat(); 572 result.append(key, value); 573 } 574 p.setDataPosition(pos + size); 575 return result; 576 } 577 578 /** Creates a {@link Double} {@link SparseArray}. */ 579 @Nullable createDoubleSparseArray(@onNull Parcel p, int header)580 public static SparseArray<Double> createDoubleSparseArray(@NonNull Parcel p, int header) { 581 final int size = readSize(p, header); 582 final int pos = p.dataPosition(); 583 if (size == 0) { 584 return null; 585 } 586 final SparseArray<Double> result = new SparseArray<Double>(); 587 final int count = p.readInt(); 588 for (int i = 0; i < count; i++) { 589 int key = p.readInt(); 590 double value = p.readDouble(); 591 result.append(key, value); 592 } 593 p.setDataPosition(pos + size); 594 return result; 595 } 596 597 /** Creates a {@link SparseLongArray}. */ 598 @Nullable createSparseLongArray(@onNull Parcel p, int header)599 public static SparseLongArray createSparseLongArray(@NonNull Parcel p, int header) { 600 final int size = readSize(p, header); 601 final int pos = p.dataPosition(); 602 if (size == 0) { 603 return null; 604 } 605 final SparseLongArray result = new SparseLongArray(); 606 final int count = p.readInt(); 607 for (int i = 0; i < count; i++) { 608 int key = p.readInt(); 609 long value = p.readLong(); 610 result.append(key, value); 611 } 612 p.setDataPosition(pos + size); 613 return result; 614 } 615 616 /** Creates a {@link String} {@link SparseArray}. */ 617 @Nullable createStringSparseArray(@onNull Parcel p, int header)618 public static SparseArray<String> createStringSparseArray(@NonNull Parcel p, int header) { 619 final int size = readSize(p, header); 620 final int pos = p.dataPosition(); 621 if (size == 0) { 622 return null; 623 } 624 final SparseArray<String> result = new SparseArray<String>(); 625 final int count = p.readInt(); 626 for (int i = 0; i < count; i++) { 627 int key = p.readInt(); 628 String value = p.readString(); 629 result.append(key, value); 630 } 631 p.setDataPosition(pos + size); 632 return result; 633 } 634 635 /** Creates a {@link Parcel} {@link SparseArray}. */ 636 @Nullable createParcelSparseArray(@onNull Parcel p, int header)637 public static SparseArray<Parcel> createParcelSparseArray(@NonNull Parcel p, int header) { 638 final int size = readSize(p, header); 639 final int pos = p.dataPosition(); 640 if (size == 0) { 641 return null; 642 } 643 final int count = p.readInt(); 644 final SparseArray<Parcel> result = new SparseArray<Parcel>(); 645 for (int i = 0; i < count; i++) { 646 int key = p.readInt(); 647 // read in the flag of whether this element is null 648 int parcelSize = p.readInt(); 649 if (parcelSize != 0) { 650 // non-null 651 int currentDataPosition = p.dataPosition(); 652 Parcel item = Parcel.obtain(); 653 item.appendFrom(p, currentDataPosition, parcelSize); 654 result.append(key, item); 655 656 // move p's data position 657 p.setDataPosition(currentDataPosition + parcelSize); 658 } else { 659 // is null 660 result.append(key, null); 661 } 662 } 663 p.setDataPosition(pos + size); 664 return result; 665 } 666 667 /** Creates typed {@link SparseArray}. */ 668 @Nullable createTypedSparseArray( @onNull Parcel p, int header, @NonNull Parcelable.Creator<T> c)669 public static <T> SparseArray<T> createTypedSparseArray( 670 @NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) { 671 final int size = readSize(p, header); 672 final int pos = p.dataPosition(); 673 if (size == 0) { 674 return null; 675 } 676 final int count = p.readInt(); 677 final SparseArray<T> result = new SparseArray<>(); 678 for (int i = 0; i < count; i++) { 679 int key = p.readInt(); 680 T value; 681 if (p.readInt() != 0) { 682 value = c.createFromParcel(p); 683 } else { 684 value = null; 685 } 686 result.append(key, value); 687 } 688 p.setDataPosition(pos + size); 689 return result; 690 } 691 692 /** Creates {@link IBinder} {@link SparseArray}. */ 693 @Nullable createIBinderSparseArray(@onNull Parcel p, int header)694 public static SparseArray<IBinder> createIBinderSparseArray(@NonNull Parcel p, int header) { 695 final int size = readSize(p, header); 696 final int pos = p.dataPosition(); 697 if (size == 0) { 698 return null; 699 } 700 final int count = p.readInt(); 701 final SparseArray<IBinder> result = new SparseArray<>(count); 702 for (int i = 0; i < count; i++) { 703 int key = p.readInt(); 704 IBinder value = p.readStrongBinder(); 705 result.append(key, value); 706 } 707 p.setDataPosition(pos + size); 708 return result; 709 } 710 711 /** Creates byte array {@link SparseArray}. */ 712 @Nullable createByteArraySparseArray(@onNull Parcel p, int header)713 public static SparseArray<byte[]> createByteArraySparseArray(@NonNull Parcel p, int header) { 714 final int size = readSize(p, header); 715 716 final int pos = p.dataPosition(); 717 if (size == 0) { 718 return null; 719 } 720 final int count = p.readInt(); 721 final SparseArray<byte[]> result = new SparseArray<byte[]>(count); 722 for (int i = 0; i < count; i++) { 723 int key = p.readInt(); 724 byte[] value = p.createByteArray(); 725 result.append(key, value); 726 } 727 p.setDataPosition(pos + size); 728 return result; 729 } 730 731 /** Creates {@link Long} {@link ArrayList}. */ 732 @Nullable createLongList(@onNull Parcel p, int header)733 public static ArrayList<Long> createLongList(@NonNull Parcel p, int header) { 734 final int size = readSize(p, header); 735 final int pos = p.dataPosition(); 736 if (size == 0) { 737 return null; 738 } 739 final ArrayList<Long> result = new ArrayList<Long>(); 740 final int count = p.readInt(); 741 for (int i = 0; i < count; i++) { 742 result.add(p.readLong()); 743 } 744 p.setDataPosition(pos + size); 745 return result; 746 } 747 748 /** Creates {@link Float} {@link ArrayList}. */ 749 @Nullable createFloatList(@onNull Parcel p, int header)750 public static ArrayList<Float> createFloatList(@NonNull Parcel p, int header) { 751 final int size = readSize(p, header); 752 final int pos = p.dataPosition(); 753 if (size == 0) { 754 return null; 755 } 756 final ArrayList<Float> result = new ArrayList<Float>(); 757 final int count = p.readInt(); 758 for (int i = 0; i < count; i++) { 759 result.add(p.readFloat()); 760 } 761 p.setDataPosition(pos + size); 762 return result; 763 } 764 765 /** Creates {@link Double} {@link ArrayList}. */ 766 @Nullable createDoubleList(@onNull Parcel p, int header)767 public static ArrayList<Double> createDoubleList(@NonNull Parcel p, int header) { 768 final int size = readSize(p, header); 769 final int pos = p.dataPosition(); 770 if (size == 0) { 771 return null; 772 } 773 final ArrayList<Double> result = new ArrayList<Double>(); 774 final int count = p.readInt(); 775 for (int i = 0; i < count; i++) { 776 result.add(p.readDouble()); 777 } 778 p.setDataPosition(pos + size); 779 return result; 780 } 781 782 /** Creates {@link String} {@link ArrayList}. */ 783 @Nullable createStringList(@onNull Parcel p, int header)784 public static ArrayList<String> createStringList(@NonNull Parcel p, int header) { 785 final int size = readSize(p, header); 786 final int pos = p.dataPosition(); 787 if (size == 0) { 788 return null; 789 } 790 final ArrayList<String> result = p.createStringArrayList(); 791 p.setDataPosition(pos + size); 792 return result; 793 } 794 795 /** Creates {@link IBinder} {@link ArrayList}. */ 796 @Nullable createIBinderList(@onNull Parcel p, int header)797 public static ArrayList<IBinder> createIBinderList(@NonNull Parcel p, int header) { 798 final int size = readSize(p, header); 799 final int pos = p.dataPosition(); 800 if (size == 0) { 801 return null; 802 } 803 final ArrayList<IBinder> result = p.createBinderArrayList(); 804 p.setDataPosition(pos + size); 805 return result; 806 } 807 808 /** Creates typed array. */ 809 @Nullable createTypedArray( @onNull Parcel p, int header, @NonNull Parcelable.Creator<T> c)810 public static <T> T[] createTypedArray( 811 @NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) { 812 final int size = readSize(p, header); 813 final int pos = p.dataPosition(); 814 if (size == 0) { 815 return null; 816 } 817 final T[] result = p.createTypedArray(c); 818 p.setDataPosition(pos + size); 819 return result; 820 } 821 822 /** Creates typed {@link ArrayList}. */ 823 @Nullable createTypedList( @onNull Parcel p, int header, @NonNull Parcelable.Creator<T> c)824 public static <T> ArrayList<T> createTypedList( 825 @NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) { 826 final int size = readSize(p, header); 827 final int pos = p.dataPosition(); 828 if (size == 0) { 829 return null; 830 } 831 final ArrayList<T> result = p.createTypedArrayList(c); 832 p.setDataPosition(pos + size); 833 return result; 834 } 835 836 /** Creates {@link Parcel}. */ 837 @Nullable createParcel(@onNull Parcel p, int header)838 public static Parcel createParcel(@NonNull Parcel p, int header) { 839 final int size = readSize(p, header); 840 final int pos = p.dataPosition(); 841 if (size == 0) { 842 return null; 843 } 844 final Parcel result = Parcel.obtain(); 845 result.appendFrom(p, pos, size); 846 p.setDataPosition(pos + size); 847 return result; 848 } 849 850 /** Creates {@link Parcel} array. */ 851 @Nullable createParcelArray(@onNull Parcel p, int header)852 public static Parcel[] createParcelArray(@NonNull Parcel p, int header) { 853 final int size = readSize(p, header); 854 final int pos = p.dataPosition(); 855 if (size == 0) { 856 return null; 857 } 858 final int length = p.readInt(); 859 final Parcel[] result = new Parcel[length]; 860 for (int i = 0; i < length; i++) { 861 int parcelSize = p.readInt(); 862 if (parcelSize != 0) { 863 int currentDataPosition = p.dataPosition(); 864 Parcel item = Parcel.obtain(); 865 item.appendFrom(p, currentDataPosition, parcelSize); 866 result[i] = item; 867 868 // move p's data position 869 p.setDataPosition(currentDataPosition + parcelSize); 870 } else { 871 result[i] = null; 872 } 873 } 874 p.setDataPosition(pos + size); 875 return result; 876 } 877 878 /** Creates {@link Parcel} {@link ArrayList}. */ 879 @Nullable createParcelList(@onNull Parcel p, int header)880 public static ArrayList<Parcel> createParcelList(@NonNull Parcel p, int header) { 881 final int size = readSize(p, header); 882 final int pos = p.dataPosition(); 883 if (size == 0) { 884 return null; 885 } 886 final int length = p.readInt(); 887 final ArrayList<Parcel> result = new ArrayList<Parcel>(); 888 for (int i = 0; i < length; i++) { 889 // read in the flag of whether this element is null 890 int parcelSize = p.readInt(); 891 if (parcelSize != 0) { 892 // non-null 893 int currentDataPosition = p.dataPosition(); 894 Parcel item = Parcel.obtain(); 895 item.appendFrom(p, currentDataPosition, parcelSize); 896 result.add(item); 897 898 // move p's data position 899 p.setDataPosition(currentDataPosition + parcelSize); 900 } else { 901 // is null 902 result.add(null); 903 } 904 } 905 p.setDataPosition(pos + size); 906 return result; 907 } 908 909 /** Reads the list. */ readList( @onNull Parcel p, int header, @SuppressWarnings("rawtypes") @NonNull List list, @Nullable ClassLoader loader)910 public static void readList( 911 @NonNull Parcel p, 912 int header, 913 @SuppressWarnings("rawtypes") @NonNull List list, 914 @Nullable ClassLoader loader) { 915 final int size = readSize(p, header); 916 final int pos = p.dataPosition(); 917 if (size == 0) { 918 return; 919 } 920 p.readList(list, loader); 921 p.setDataPosition(pos + size); 922 } 923 924 /** Ensures at end. */ ensureAtEnd(@onNull Parcel parcel, int end)925 public static void ensureAtEnd(@NonNull Parcel parcel, int end) { 926 if (parcel.dataPosition() != end) { 927 throw new ParseException("Overread allowed size end=" + end, parcel); 928 } 929 } 930 } 931