931 lines
30 KiB
Java
931 lines
30 KiB
Java
/*
|
|
* Copyright (C) 2023 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.app.appsearch.safeparcel;
|
|
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.app.PendingIntent;
|
|
import android.os.Bundle;
|
|
import android.os.IBinder;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.util.SparseArray;
|
|
import android.util.SparseBooleanArray;
|
|
import android.util.SparseIntArray;
|
|
import android.util.SparseLongArray;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.math.BigInteger;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Functions to read in a safe parcel.
|
|
*
|
|
* @hide
|
|
*/
|
|
// Include the SafeParcel source code directly in AppSearch until it gets officially open-sourced.
|
|
public class SafeParcelReader {
|
|
/** class to parse the exception. */
|
|
public static class ParseException extends RuntimeException {
|
|
public ParseException(@NonNull String message, @NonNull Parcel p) {
|
|
super(message + " Parcel: pos=" + p.dataPosition() + " size=" + p.dataSize());
|
|
}
|
|
}
|
|
|
|
private SafeParcelReader() {}
|
|
|
|
/** Reads the header. */
|
|
public static int readHeader(@NonNull Parcel p) {
|
|
return p.readInt();
|
|
}
|
|
|
|
/** Gets the id for the field. */
|
|
public static int getFieldId(int header) {
|
|
return header & 0x0000ffff;
|
|
}
|
|
|
|
/** Reads the size. */
|
|
public static int readSize(@NonNull Parcel p, int header) {
|
|
if ((header & 0xffff0000) != 0xffff0000) {
|
|
return (header >> 16) & 0x0000ffff;
|
|
} else {
|
|
return p.readInt();
|
|
}
|
|
}
|
|
|
|
/** Skips the unknown field. */
|
|
public static void skipUnknownField(@NonNull Parcel p, int header) {
|
|
int size = readSize(p, header);
|
|
p.setDataPosition(p.dataPosition() + size);
|
|
}
|
|
|
|
private static void readAndEnforceSize(@NonNull Parcel p, int header, int required) {
|
|
final int size = readSize(p, header);
|
|
if (size != required) {
|
|
throw new ParseException(
|
|
"Expected size "
|
|
+ required
|
|
+ " got "
|
|
+ size
|
|
+ " (0x"
|
|
+ Integer.toHexString(size)
|
|
+ ")",
|
|
p);
|
|
}
|
|
}
|
|
|
|
private static void enforceSize(@NonNull Parcel p, int header, int size, int required) {
|
|
if (size != required) {
|
|
throw new ParseException(
|
|
"Expected size "
|
|
+ required
|
|
+ " got "
|
|
+ size
|
|
+ " (0x"
|
|
+ Integer.toHexString(size)
|
|
+ ")",
|
|
p);
|
|
}
|
|
}
|
|
|
|
/** Returns the end position of the object in the parcel. */
|
|
public static int validateObjectHeader(@NonNull Parcel p) {
|
|
final int header = readHeader(p);
|
|
final int size = readSize(p, header);
|
|
final int start = p.dataPosition();
|
|
if (getFieldId(header) != SafeParcelWriter.OBJECT_HEADER) {
|
|
throw new ParseException(
|
|
"Expected object header. Got 0x" + Integer.toHexString(header), p);
|
|
}
|
|
final int end = start + size;
|
|
if (end < start || end > p.dataSize()) {
|
|
throw new ParseException("Size read is invalid start=" + start + " end=" + end, p);
|
|
}
|
|
return end;
|
|
}
|
|
|
|
/** Reads a boolean. */
|
|
public static boolean readBoolean(@NonNull Parcel p, int header) {
|
|
readAndEnforceSize(p, header, 4);
|
|
return p.readInt() != 0;
|
|
}
|
|
|
|
/** Reads a {@link Boolean} object. */
|
|
@Nullable
|
|
public static Boolean readBooleanObject(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
if (size == 0) {
|
|
return null;
|
|
} else {
|
|
enforceSize(p, header, size, 4);
|
|
return p.readInt() != 0;
|
|
}
|
|
}
|
|
|
|
/** Reads a byte. */
|
|
public static byte readByte(@NonNull Parcel p, int header) {
|
|
readAndEnforceSize(p, header, 4);
|
|
return (byte) p.readInt();
|
|
}
|
|
|
|
/** Reads a char. */
|
|
public static char readChar(@NonNull Parcel p, int header) {
|
|
readAndEnforceSize(p, header, 4);
|
|
return (char) p.readInt();
|
|
}
|
|
|
|
/** Reads a short. */
|
|
public static short readShort(@NonNull Parcel p, int header) {
|
|
readAndEnforceSize(p, header, 4);
|
|
return (short) p.readInt();
|
|
}
|
|
|
|
/** Reads an int. */
|
|
public static int readInt(@NonNull Parcel p, int header) {
|
|
readAndEnforceSize(p, header, 4);
|
|
return p.readInt();
|
|
}
|
|
|
|
/** Reads an {@link Integer} object. */
|
|
@Nullable
|
|
public static Integer readIntegerObject(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
if (size == 0) {
|
|
return null;
|
|
} else {
|
|
enforceSize(p, header, size, 4);
|
|
return p.readInt();
|
|
}
|
|
}
|
|
|
|
/** Reads a long. */
|
|
public static long readLong(@NonNull Parcel p, int header) {
|
|
readAndEnforceSize(p, header, 8);
|
|
return p.readLong();
|
|
}
|
|
|
|
/** Reads a {@link Long} object. */
|
|
@Nullable
|
|
public static Long readLongObject(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
if (size == 0) {
|
|
return null;
|
|
} else {
|
|
enforceSize(p, header, size, 8);
|
|
return p.readLong();
|
|
}
|
|
}
|
|
|
|
/** Creates a {@link BigInteger}. */
|
|
@Nullable
|
|
public static BigInteger createBigInteger(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final byte[] val = p.createByteArray();
|
|
p.setDataPosition(pos + size);
|
|
return new BigInteger(val);
|
|
}
|
|
|
|
/** Reads a float. */
|
|
public static float readFloat(@NonNull Parcel p, int header) {
|
|
readAndEnforceSize(p, header, 4);
|
|
return p.readFloat();
|
|
}
|
|
|
|
/** Reads a {@link Float}. */
|
|
@Nullable
|
|
public static Float readFloatObject(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
if (size == 0) {
|
|
return null;
|
|
} else {
|
|
enforceSize(p, header, size, 4);
|
|
return p.readFloat();
|
|
}
|
|
}
|
|
|
|
/** Reads a double. */
|
|
public static double readDouble(@NonNull Parcel p, int header) {
|
|
readAndEnforceSize(p, header, 8);
|
|
return p.readDouble();
|
|
}
|
|
|
|
/** Reads a {@link Double}. */
|
|
@Nullable
|
|
public static Double readDoubleObject(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
if (size == 0) {
|
|
return null;
|
|
} else {
|
|
enforceSize(p, header, size, 8);
|
|
return p.readDouble();
|
|
}
|
|
}
|
|
|
|
/** Creates a {@link BigDecimal}. */
|
|
@Nullable
|
|
public static BigDecimal createBigDecimal(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final byte[] unscaledValue = p.createByteArray();
|
|
final int scale = p.readInt();
|
|
p.setDataPosition(pos + size);
|
|
return new BigDecimal(new BigInteger(unscaledValue), scale);
|
|
}
|
|
|
|
/** Creates a {@link String}. */
|
|
@Nullable
|
|
public static String createString(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final String result = p.readString();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Reads an {@link IBinder}. */
|
|
@Nullable
|
|
public static IBinder readIBinder(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final IBinder result = p.readStrongBinder();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Reads a {@link PendingIntent}. */
|
|
@Nullable
|
|
public static PendingIntent readPendingIntent(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final PendingIntent result = PendingIntent.readPendingIntentOrNullFromParcel(p);
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link Parcelable}. */
|
|
@Nullable
|
|
public static <T extends Parcelable> T createParcelable(
|
|
@NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> creator) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final T result = creator.createFromParcel(p);
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link Bundle}. */
|
|
@Nullable
|
|
public static Bundle createBundle(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final Bundle result = p.readBundle();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a byte array. */
|
|
@Nullable
|
|
public static byte[] createByteArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final byte[] result = p.createByteArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a byte array array. */
|
|
@Nullable
|
|
public static byte[][] createByteArrayArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int length = p.readInt();
|
|
final byte[][] result = new byte[length][];
|
|
for (int i = 0; i < length; i++) {
|
|
result[i] = p.createByteArray();
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a boolean array array. */
|
|
@Nullable
|
|
public static boolean[] createBooleanArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final boolean[] result = p.createBooleanArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a char array. */
|
|
@Nullable
|
|
public static char[] createCharArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final char[] result = p.createCharArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates an int array. */
|
|
@Nullable
|
|
public static int[] createIntArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int[] result = p.createIntArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a long array. */
|
|
@Nullable
|
|
public static long[] createLongArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final long[] result = p.createLongArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link BigInteger} array. */
|
|
@Nullable
|
|
public static BigInteger[] createBigIntegerArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int length = p.readInt();
|
|
final BigInteger[] result = new BigInteger[length];
|
|
for (int i = 0; i < length; i++) {
|
|
result[i] = new BigInteger(p.createByteArray());
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a float array. */
|
|
@Nullable
|
|
public static float[] createFloatArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final float[] result = p.createFloatArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a double array. */
|
|
@Nullable
|
|
public static double[] createDoubleArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final double[] result = p.createDoubleArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link BigDecimal} array. */
|
|
@Nullable
|
|
public static BigDecimal[] createBigDecimalArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int length = p.readInt();
|
|
final BigDecimal[] result = new BigDecimal[length];
|
|
for (int i = 0; i < length; i++) {
|
|
byte[] unscaledValue = p.createByteArray();
|
|
int scale = p.readInt();
|
|
result[i] = new BigDecimal(new BigInteger(unscaledValue), scale);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link String} array. */
|
|
@Nullable
|
|
public static String[] createStringArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final String[] result = p.createStringArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link IBinder} array. */
|
|
@Nullable
|
|
public static IBinder[] createIBinderArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final IBinder[] result = p.createBinderArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link Boolean} list. */
|
|
@Nullable
|
|
public static ArrayList<Boolean> createBooleanList(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final ArrayList<Boolean> result = new ArrayList<Boolean>();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
result.add(p.readInt() != 0 ? true : false);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link Integer} list. */
|
|
@Nullable
|
|
public static ArrayList<Integer> createIntegerList(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final ArrayList<Integer> result = new ArrayList<Integer>();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
result.add(p.readInt());
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link SparseBooleanArray}. */
|
|
@Nullable
|
|
public static SparseBooleanArray createSparseBooleanArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
SparseBooleanArray result = p.readSparseBooleanArray();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link SparseIntArray}. */
|
|
@Nullable
|
|
public static SparseIntArray createSparseIntArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final SparseIntArray result = new SparseIntArray();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
int value = p.readInt();
|
|
result.append(key, value);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link Float} {@link SparseArray}. */
|
|
@Nullable
|
|
public static SparseArray<Float> createFloatSparseArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final SparseArray<Float> result = new SparseArray<Float>();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
float value = p.readFloat();
|
|
result.append(key, value);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link Double} {@link SparseArray}. */
|
|
@Nullable
|
|
public static SparseArray<Double> createDoubleSparseArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final SparseArray<Double> result = new SparseArray<Double>();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
double value = p.readDouble();
|
|
result.append(key, value);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link SparseLongArray}. */
|
|
@Nullable
|
|
public static SparseLongArray createSparseLongArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final SparseLongArray result = new SparseLongArray();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
long value = p.readLong();
|
|
result.append(key, value);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link String} {@link SparseArray}. */
|
|
@Nullable
|
|
public static SparseArray<String> createStringSparseArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final SparseArray<String> result = new SparseArray<String>();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
String value = p.readString();
|
|
result.append(key, value);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates a {@link Parcel} {@link SparseArray}. */
|
|
@Nullable
|
|
public static SparseArray<Parcel> createParcelSparseArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int count = p.readInt();
|
|
final SparseArray<Parcel> result = new SparseArray<Parcel>();
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
// read in the flag of whether this element is null
|
|
int parcelSize = p.readInt();
|
|
if (parcelSize != 0) {
|
|
// non-null
|
|
int currentDataPosition = p.dataPosition();
|
|
Parcel item = Parcel.obtain();
|
|
item.appendFrom(p, currentDataPosition, parcelSize);
|
|
result.append(key, item);
|
|
|
|
// move p's data position
|
|
p.setDataPosition(currentDataPosition + parcelSize);
|
|
} else {
|
|
// is null
|
|
result.append(key, null);
|
|
}
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates typed {@link SparseArray}. */
|
|
@Nullable
|
|
public static <T> SparseArray<T> createTypedSparseArray(
|
|
@NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int count = p.readInt();
|
|
final SparseArray<T> result = new SparseArray<>();
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
T value;
|
|
if (p.readInt() != 0) {
|
|
value = c.createFromParcel(p);
|
|
} else {
|
|
value = null;
|
|
}
|
|
result.append(key, value);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link IBinder} {@link SparseArray}. */
|
|
@Nullable
|
|
public static SparseArray<IBinder> createIBinderSparseArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int count = p.readInt();
|
|
final SparseArray<IBinder> result = new SparseArray<>(count);
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
IBinder value = p.readStrongBinder();
|
|
result.append(key, value);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates byte array {@link SparseArray}. */
|
|
@Nullable
|
|
public static SparseArray<byte[]> createByteArraySparseArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int count = p.readInt();
|
|
final SparseArray<byte[]> result = new SparseArray<byte[]>(count);
|
|
for (int i = 0; i < count; i++) {
|
|
int key = p.readInt();
|
|
byte[] value = p.createByteArray();
|
|
result.append(key, value);
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link Long} {@link ArrayList}. */
|
|
@Nullable
|
|
public static ArrayList<Long> createLongList(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final ArrayList<Long> result = new ArrayList<Long>();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
result.add(p.readLong());
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link Float} {@link ArrayList}. */
|
|
@Nullable
|
|
public static ArrayList<Float> createFloatList(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final ArrayList<Float> result = new ArrayList<Float>();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
result.add(p.readFloat());
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link Double} {@link ArrayList}. */
|
|
@Nullable
|
|
public static ArrayList<Double> createDoubleList(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final ArrayList<Double> result = new ArrayList<Double>();
|
|
final int count = p.readInt();
|
|
for (int i = 0; i < count; i++) {
|
|
result.add(p.readDouble());
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link String} {@link ArrayList}. */
|
|
@Nullable
|
|
public static ArrayList<String> createStringList(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final ArrayList<String> result = p.createStringArrayList();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link IBinder} {@link ArrayList}. */
|
|
@Nullable
|
|
public static ArrayList<IBinder> createIBinderList(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final ArrayList<IBinder> result = p.createBinderArrayList();
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates typed array. */
|
|
@Nullable
|
|
public static <T> T[] createTypedArray(
|
|
@NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final T[] result = p.createTypedArray(c);
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates typed {@link ArrayList}. */
|
|
@Nullable
|
|
public static <T> ArrayList<T> createTypedList(
|
|
@NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final ArrayList<T> result = p.createTypedArrayList(c);
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link Parcel}. */
|
|
@Nullable
|
|
public static Parcel createParcel(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final Parcel result = Parcel.obtain();
|
|
result.appendFrom(p, pos, size);
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link Parcel} array. */
|
|
@Nullable
|
|
public static Parcel[] createParcelArray(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int length = p.readInt();
|
|
final Parcel[] result = new Parcel[length];
|
|
for (int i = 0; i < length; i++) {
|
|
int parcelSize = p.readInt();
|
|
if (parcelSize != 0) {
|
|
int currentDataPosition = p.dataPosition();
|
|
Parcel item = Parcel.obtain();
|
|
item.appendFrom(p, currentDataPosition, parcelSize);
|
|
result[i] = item;
|
|
|
|
// move p's data position
|
|
p.setDataPosition(currentDataPosition + parcelSize);
|
|
} else {
|
|
result[i] = null;
|
|
}
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Creates {@link Parcel} {@link ArrayList}. */
|
|
@Nullable
|
|
public static ArrayList<Parcel> createParcelList(@NonNull Parcel p, int header) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return null;
|
|
}
|
|
final int length = p.readInt();
|
|
final ArrayList<Parcel> result = new ArrayList<Parcel>();
|
|
for (int i = 0; i < length; i++) {
|
|
// read in the flag of whether this element is null
|
|
int parcelSize = p.readInt();
|
|
if (parcelSize != 0) {
|
|
// non-null
|
|
int currentDataPosition = p.dataPosition();
|
|
Parcel item = Parcel.obtain();
|
|
item.appendFrom(p, currentDataPosition, parcelSize);
|
|
result.add(item);
|
|
|
|
// move p's data position
|
|
p.setDataPosition(currentDataPosition + parcelSize);
|
|
} else {
|
|
// is null
|
|
result.add(null);
|
|
}
|
|
}
|
|
p.setDataPosition(pos + size);
|
|
return result;
|
|
}
|
|
|
|
/** Reads the list. */
|
|
public static void readList(
|
|
@NonNull Parcel p,
|
|
int header,
|
|
@SuppressWarnings("rawtypes") @NonNull List list,
|
|
@Nullable ClassLoader loader) {
|
|
final int size = readSize(p, header);
|
|
final int pos = p.dataPosition();
|
|
if (size == 0) {
|
|
return;
|
|
}
|
|
p.readList(list, loader);
|
|
p.setDataPosition(pos + size);
|
|
}
|
|
|
|
/** Ensures at end. */
|
|
public static void ensureAtEnd(@NonNull Parcel parcel, int end) {
|
|
if (parcel.dataPosition() != end) {
|
|
throw new ParseException("Overread allowed size end=" + end, parcel);
|
|
}
|
|
}
|
|
}
|