Add support for Lists

This commit is contained in:
mar-v-in 2015-02-10 03:03:27 +01:00
parent 3efecf38ca
commit a650ca5bea
5 changed files with 313 additions and 279 deletions

View File

@ -20,112 +20,125 @@ import android.os.IBinder;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
public class SafeParcelReader { public class SafeParcelReader {
public static int halfOf(int i) { public static int halfOf(int i) {
return i & 0xFFFF; return i & 0xFFFF;
} }
public static int readSingleInt(Parcel parcel) { public static int readSingleInt(Parcel parcel) {
return parcel.readInt(); return parcel.readInt();
} }
private static int readStart(Parcel parcel, int first) { private static int readStart(Parcel parcel, int first) {
if ((first & 0xFFFF0000) != -65536) if ((first & 0xFFFF0000) != -65536)
return first >> 16 & 0xFFFF; return first >> 16 & 0xFFFF;
return parcel.readInt(); return parcel.readInt();
} }
private static void readStart(Parcel parcel, int position, int length) { private static void readStart(Parcel parcel, int position, int length) {
int i = readStart(parcel, position); int i = readStart(parcel, position);
if (i != length) if (i != length)
throw new ReadException("Expected size " + length + " got " + i + " (0x" + Integer.toHexString(i) + ")", parcel); throw new ReadException("Expected size " + length + " got " + i + " (0x" + Integer.toHexString(i) + ")", parcel);
} }
public static int readStart(Parcel parcel) { public static int readStart(Parcel parcel) {
int first = readSingleInt(parcel); int first = readSingleInt(parcel);
int length = readStart(parcel, first); int length = readStart(parcel, first);
int start = parcel.dataPosition(); int start = parcel.dataPosition();
if (halfOf(first) != SafeParcelable.SAFE_PARCEL_MAGIC) if (halfOf(first) != SafeParcelable.SAFE_PARCEL_MAGIC)
throw new ReadException("Expected object header. Got 0x" + Integer.toHexString(first), parcel); throw new ReadException("Expected object header. Got 0x" + Integer.toHexString(first), parcel);
int end = start + length; int end = start + length;
if ((end < start) || (end > parcel.dataSize())) if ((end < start) || (end > parcel.dataSize()))
throw new ReadException("Size read is invalid start=" + start + " end=" + end, parcel); throw new ReadException("Size read is invalid start=" + start + " end=" + end, parcel);
return end; return end;
} }
public static int readInt(Parcel parcel, int position) { public static int readInt(Parcel parcel, int position) {
readStart(parcel, position, 4); readStart(parcel, position, 4);
return parcel.readInt(); return parcel.readInt();
} }
public static byte readByte(Parcel parcel, int position) { public static byte readByte(Parcel parcel, int position) {
readStart(parcel, position, 4); readStart(parcel, position, 4);
return (byte) parcel.readInt(); return (byte) parcel.readInt();
} }
public static short readShort(Parcel parcel, int position) { public static short readShort(Parcel parcel, int position) {
readStart(parcel, position, 4); readStart(parcel, position, 4);
return (short) parcel.readInt(); return (short) parcel.readInt();
} }
public static boolean readBool(Parcel parcel, int position) { public static boolean readBool(Parcel parcel, int position) {
readStart(parcel, position, 4); readStart(parcel, position, 4);
return parcel.readInt() != 0; return parcel.readInt() != 0;
} }
public static long readLong(Parcel parcel, int position) { public static long readLong(Parcel parcel, int position) {
readStart(parcel, position, 8); readStart(parcel, position, 8);
return parcel.readLong(); return parcel.readLong();
} }
public static float readFloat(Parcel parcel, int position) { public static float readFloat(Parcel parcel, int position) {
readStart(parcel, position, 4); readStart(parcel, position, 4);
return parcel.readFloat(); return parcel.readFloat();
} }
public static double readDouble(Parcel parcel, int position) { public static double readDouble(Parcel parcel, int position) {
readStart(parcel, position, 8); readStart(parcel, position, 8);
return parcel.readDouble(); return parcel.readDouble();
} }
public static String readString(Parcel parcel, int position) { public static String readString(Parcel parcel, int position) {
int length = readStart(parcel, position); int length = readStart(parcel, position);
int start = parcel.dataPosition(); int start = parcel.dataPosition();
if (length == 0) if (length == 0)
return null; return null;
String string = parcel.readString(); String string = parcel.readString();
parcel.setDataPosition(start + length); parcel.setDataPosition(start + length);
return string; return string;
} }
public static IBinder readBinder(Parcel parcel, int position) { public static IBinder readBinder(Parcel parcel, int position) {
int length = readStart(parcel, position); int length = readStart(parcel, position);
int start = parcel.dataPosition(); int start = parcel.dataPosition();
if (length == 0) if (length == 0)
return null; return null;
IBinder binder = parcel.readStrongBinder(); IBinder binder = parcel.readStrongBinder();
parcel.setDataPosition(start + length); parcel.setDataPosition(start + length);
return binder; return binder;
} }
public static <T extends Parcelable> T readParcelable(Parcel parcel, int position, Parcelable.Creator<T> creator) { public static <T extends Parcelable> T readParcelable(Parcel parcel, int position, Parcelable.Creator<T> creator) {
int length = readStart(parcel, position); int length = readStart(parcel, position);
int start = parcel.dataPosition(); int start = parcel.dataPosition();
if (length == 0) if (length == 0)
return null; return null;
T t = creator.createFromParcel(parcel); T t = creator.createFromParcel(parcel);
parcel.setDataPosition(start + length); parcel.setDataPosition(start + length);
return t; return t;
} }
public static void skip(Parcel parcel, int position) { public static ArrayList readList(Parcel parcel, int position, ClassLoader classLoader) {
int i = readStart(parcel, position); int length = readStart(parcel, position);
parcel.setDataPosition(parcel.dataPosition() + i); int start = parcel.dataPosition();
} if (length == 0)
return null;
ArrayList list = parcel.readArrayList(classLoader);
parcel.setDataPosition(start + length);
return list;
}
public static class ReadException extends RuntimeException { public static void skip(Parcel parcel, int position) {
public ReadException(String message, Parcel parcel) { int i = readStart(parcel, position);
super(message); parcel.setDataPosition(parcel.dataPosition() + i);
} }
}
public static class ReadException extends RuntimeException {
public ReadException(String message, Parcel parcel) {
super(message);
}
}
} }

View File

@ -8,7 +8,9 @@ import android.util.Log;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
public class SafeParcelUtil { public class SafeParcelUtil {
@ -104,6 +106,15 @@ public class SafeParcelUtil {
} }
} }
private static ClassLoader getClassLoader(Field field) {
try {
String type = field.getAnnotation(SafeParceled.class).subType();
return Class.forName(type).getClassLoader();
} catch (ClassNotFoundException e) {
return ClassLoader.getSystemClassLoader();
}
}
private static void writeField(SafeParcelable object, Parcel parcel, Field field, int flags) private static void writeField(SafeParcelable object, Parcel parcel, Field field, int flags)
throws IllegalAccessException { throws IllegalAccessException {
int num = field.getAnnotation(SafeParceled.class).value(); int num = field.getAnnotation(SafeParceled.class).value();
@ -117,6 +128,9 @@ public class SafeParcelUtil {
case Binder: case Binder:
SafeParcelWriter.write(parcel, num, (IBinder) field.get(object), mayNull); SafeParcelWriter.write(parcel, num, (IBinder) field.get(object), mayNull);
break; break;
case List:
SafeParcelWriter.write(parcel, num, (List) field.get(object), mayNull);
break;
case Integer: case Integer:
SafeParcelWriter.write(parcel, num, (Integer) field.get(object)); SafeParcelWriter.write(parcel, num, (Integer) field.get(object));
break; break;
@ -151,6 +165,9 @@ public class SafeParcelUtil {
field.set(object, SafeParcelReader.readBinder(parcel, field.set(object, SafeParcelReader.readBinder(parcel,
position)); position));
break; break;
case List:
field.set(object, SafeParcelReader.readList(parcel, position, getClassLoader(field)));
break;
case Integer: case Integer:
field.set(object, SafeParcelReader.readInt(parcel, position)); field.set(object, SafeParcelReader.readInt(parcel, position));
break; break;
@ -173,13 +190,15 @@ public class SafeParcelUtil {
} }
private enum SafeParcelType { private enum SafeParcelType {
Parcelable, Binder, Integer, Long, Boolean, Float, Double, String; Parcelable, Binder, Integer, Long, Boolean, Float, Double, String, List;
public static SafeParcelType fromClass(Class clazz) { public static SafeParcelType fromClass(Class clazz) {
if (Parcelable.class.isAssignableFrom(clazz)) if (Parcelable.class.isAssignableFrom(clazz))
return Parcelable; return Parcelable;
if (IBinder.class.isAssignableFrom(clazz)) if (IBinder.class.isAssignableFrom(clazz))
return Binder; return Binder;
if (clazz == List.class || clazz == ArrayList.class)
return List;
if (clazz == int.class || clazz == Integer.class) if (clazz == int.class || clazz == Integer.class)
return Integer; return Integer;
if (clazz == boolean.class || clazz == Boolean.class) if (clazz == boolean.class || clazz == Boolean.class)

View File

@ -25,211 +25,211 @@ import java.util.List;
public class SafeParcelWriter { public class SafeParcelWriter {
private static void writeStart(Parcel parcel, int position, int length) { private static void writeStart(Parcel parcel, int position, int length) {
if (length >= 65535) { if (length >= 65535) {
parcel.writeInt(0xFFFF0000 | position); parcel.writeInt(0xFFFF0000 | position);
parcel.writeInt(length); parcel.writeInt(length);
} else { } else {
parcel.writeInt(length << 16 | position); parcel.writeInt(length << 16 | position);
} }
} }
public static int writeStart(Parcel parcel) { public static int writeStart(Parcel parcel) {
return writeStart(parcel, SafeParcelable.SAFE_PARCEL_MAGIC); return writeStart(parcel, SafeParcelable.SAFE_PARCEL_MAGIC);
} }
private static int writeStart(Parcel parcel, int position) { private static int writeStart(Parcel parcel, int position) {
parcel.writeInt(0xFFFF0000 | position); parcel.writeInt(0xFFFF0000 | position);
parcel.writeInt(0); parcel.writeInt(0);
return parcel.dataPosition(); return parcel.dataPosition();
} }
public static void writeEnd(Parcel parcel, int start) { public static void writeEnd(Parcel parcel, int start) {
int end = parcel.dataPosition(); int end = parcel.dataPosition();
int length = end - start; int length = end - start;
parcel.setDataPosition(start - 4); parcel.setDataPosition(start - 4);
parcel.writeInt(length); parcel.writeInt(length);
parcel.setDataPosition(end); parcel.setDataPosition(end);
} }
public static void write(Parcel parcel, int position, Boolean val) { public static void write(Parcel parcel, int position, Boolean val) {
if (val == null) return; if (val == null) return;
writeStart(parcel, position, 4); writeStart(parcel, position, 4);
parcel.writeInt(val ? 1 : 0); parcel.writeInt(val ? 1 : 0);
} }
public static void write(Parcel parcel, int position, Byte val) { public static void write(Parcel parcel, int position, Byte val) {
if (val == null) return; if (val == null) return;
writeStart(parcel, position, 4); writeStart(parcel, position, 4);
parcel.writeInt(val); parcel.writeInt(val);
} }
public static void write(Parcel parcel, int position, Short val) { public static void write(Parcel parcel, int position, Short val) {
if (val == null) return; if (val == null) return;
writeStart(parcel, position, 4); writeStart(parcel, position, 4);
parcel.writeInt(val); parcel.writeInt(val);
} }
public static void write(Parcel parcel, int position, Integer val) { public static void write(Parcel parcel, int position, Integer val) {
if (val == null) return; if (val == null) return;
writeStart(parcel, position, 4); writeStart(parcel, position, 4);
parcel.writeInt(val); parcel.writeInt(val);
} }
public static void write(Parcel parcel, int position, Long val) { public static void write(Parcel parcel, int position, Long val) {
if (val == null) return; if (val == null) return;
writeStart(parcel, position, 8); writeStart(parcel, position, 8);
parcel.writeLong(val); parcel.writeLong(val);
} }
public static void write(Parcel parcel, int position, Float val) { public static void write(Parcel parcel, int position, Float val) {
if (val == null) return; if (val == null) return;
writeStart(parcel, position, 4); writeStart(parcel, position, 4);
parcel.writeFloat(val); parcel.writeFloat(val);
} }
public static void write(Parcel parcel, int position, Double val) { public static void write(Parcel parcel, int position, Double val) {
if (val == null) return; if (val == null) return;
writeStart(parcel, position, 8); writeStart(parcel, position, 8);
parcel.writeDouble(val); parcel.writeDouble(val);
} }
public static void write(Parcel parcel, int position, String val, boolean mayNull) { public static void write(Parcel parcel, int position, String val, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.writeString(val); parcel.writeString(val);
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
public static void write(Parcel parcel, int position, Parcelable val, int flags, boolean mayNull) { public static void write(Parcel parcel, int position, Parcelable val, int flags, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
val.writeToParcel(parcel, flags); val.writeToParcel(parcel, flags);
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
public static void write(Parcel parcel, int position, Bundle val, boolean mayNull) { public static void write(Parcel parcel, int position, Bundle val, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.writeBundle(val); parcel.writeBundle(val);
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
public static void write(Parcel parcel, int position, byte[] val, boolean mayNull) { public static void write(Parcel parcel, int position, byte[] val, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.writeByteArray(val); parcel.writeByteArray(val);
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
public static void write(Parcel parcel, int position, String[] val, boolean mayNull) { public static void write(Parcel parcel, int position, String[] val, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.writeStringArray(val); parcel.writeStringArray(val);
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
public static void writeStringList(Parcel parcel, int position, List<String> val, boolean mayNull) { public static void writeStringList(Parcel parcel, int position, List<String> val, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.writeStringList(val); parcel.writeStringList(val);
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
private static <T extends Parcelable> void writeArrayPart(Parcel parcel, T val, int flags) { private static <T extends Parcelable> void writeArrayPart(Parcel parcel, T val, int flags) {
int before = parcel.dataPosition(); int before = parcel.dataPosition();
parcel.writeInt(1); parcel.writeInt(1);
int start = parcel.dataPosition(); int start = parcel.dataPosition();
val.writeToParcel(parcel, flags); val.writeToParcel(parcel, flags);
int end = parcel.dataPosition(); int end = parcel.dataPosition();
parcel.setDataPosition(before); parcel.setDataPosition(before);
parcel.writeInt(end - start); parcel.writeInt(end - start);
parcel.setDataPosition(end); parcel.setDataPosition(end);
} }
public static <T extends Parcelable> void write(Parcel parcel, int position, T[] val, int flags, boolean mayNull) { public static <T extends Parcelable> void write(Parcel parcel, int position, T[] val, int flags, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.writeInt(val.length); parcel.writeInt(val.length);
for (T t : val) { for (T t : val) {
if (t == null) { if (t == null) {
parcel.writeInt(0); parcel.writeInt(0);
} else { } else {
writeArrayPart(parcel, t, flags); writeArrayPart(parcel, t, flags);
} }
} }
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
public static void write(Parcel parcel, int position, Parcel val, boolean mayNull) { public static void write(Parcel parcel, int position, Parcel val, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.appendFrom(val, 0, val.dataSize()); parcel.appendFrom(val, 0, val.dataSize());
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
public static void write(Parcel parcel, int position, List val, boolean mayNull) { public static void write(Parcel parcel, int position, List val, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.writeList(val); parcel.writeList(val);
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
public static void write(Parcel parcel, int position, IBinder val, boolean mayNull) { public static void write(Parcel parcel, int position, IBinder val, boolean mayNull) {
if (val == null) { if (val == null) {
if (mayNull) { if (mayNull) {
writeStart(parcel, position, 0); writeStart(parcel, position, 0);
} }
} else { } else {
int start = writeStart(parcel, position); int start = writeStart(parcel, position);
parcel.writeStrongBinder(val); parcel.writeStrongBinder(val);
writeEnd(parcel, start); writeEnd(parcel, start);
} }
} }
} }

View File

@ -19,6 +19,6 @@ package org.microg.safeparcel;
import android.os.Parcelable; import android.os.Parcelable;
public interface SafeParcelable extends Parcelable { public interface SafeParcelable extends Parcelable {
public static final String NULL = "SAFE_PARCELABLE_NULL_STRING"; public static final String NULL = "SAFE_PARCELABLE_NULL_STRING";
int SAFE_PARCEL_MAGIC = 20293; int SAFE_PARCEL_MAGIC = 20293;
} }

View File

@ -11,4 +11,6 @@ public @interface SafeParceled {
int value(); int value();
boolean mayNull() default false; boolean mayNull() default false;
String subType() default "undefined";
} }