Methods Summary |
---|
private boolean | checkMetadataId(int val)Check val is either a system id or a custom one.
if (val <= ANY || (LAST_SYSTEM < val && val < FIRST_CUSTOM)) {
Log.e(TAG, "Invalid metadata ID " + val);
return false;
}
return true;
|
private void | checkType(int key, int expectedType)Check the type of the data match what is expected.
final int pos = mKeyToPosMap.get(key);
mParcel.setDataPosition(pos);
final int type = mParcel.readInt();
if (type != expectedType) {
throw new IllegalStateException("Wrong type " + expectedType + " but got " + type);
}
|
public static int | firstCustomId() return FIRST_CUSTOM;
|
public boolean | getBoolean(int key)Get the boolean value indicated by key
checkType(key, BOOLEAN_VAL);
return mParcel.readInt() == 1;
|
public byte[] | getByteArray(int key){@hide}
checkType(key, BYTE_ARRAY_VAL);
return mParcel.createByteArray();
|
public java.util.Date | getDate(int key){@hide}
checkType(key, DATE_VAL);
final long timeSinceEpoch = mParcel.readLong();
final String timeZone = mParcel.readString();
if (timeZone.length() == 0) {
return new Date(timeSinceEpoch);
} else {
TimeZone tz = TimeZone.getTimeZone(timeZone);
Calendar cal = Calendar.getInstance(tz);
cal.setTimeInMillis(timeSinceEpoch);
return cal.getTime();
}
|
public double | getDouble(int key){@hide}
checkType(key, DOUBLE_VAL);
return mParcel.readDouble();
|
public int | getInt(int key){@hide}
checkType(key, INTEGER_VAL);
return mParcel.readInt();
|
public long | getLong(int key){@hide}
checkType(key, LONG_VAL); /**
* {@hide}
*/
return mParcel.readLong();
|
public java.lang.String | getString(int key){@hide}
checkType(key, STRING_VAL);
return mParcel.readString();
|
public boolean | has(int metadataId)
if (!checkMetadataId(metadataId)) {
throw new IllegalArgumentException("Invalid key: " + metadataId);
}
return mKeyToPosMap.containsKey(metadataId);
|
public java.util.Set | keySet()
return mKeyToPosMap.keySet();
|
public static int | lastSytemId() return LAST_SYSTEM;
|
public static int | lastType() return LAST_TYPE;
|
public boolean | parse(android.os.Parcel parcel)Check a parcel containing metadata is well formed. The header
is checked as well as the individual records format. However, the
data inside the record is not checked because we do lazy access
(we check/unmarshall only data the user asks for.)
Format of a metadata parcel:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| metadata total size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 'M' | 'E' | 'T' | 'A' |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| .... metadata records .... |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
if (parcel.dataAvail() < kMetaHeaderSize) {
Log.e(TAG, "Not enough data " + parcel.dataAvail());
return false;
}
final int pin = parcel.dataPosition(); // to roll back in case of errors.
final int size = parcel.readInt();
// The extra kInt32Size below is to account for the int32 'size' just read.
if (parcel.dataAvail() + kInt32Size < size || size < kMetaHeaderSize) {
Log.e(TAG, "Bad size " + size + " avail " + parcel.dataAvail() + " position " + pin);
parcel.setDataPosition(pin);
return false;
}
// Checks if the 'M' 'E' 'T' 'A' marker is present.
final int kShouldBeMetaMarker = parcel.readInt();
if (kShouldBeMetaMarker != kMetaMarker ) {
Log.e(TAG, "Marker missing " + Integer.toHexString(kShouldBeMetaMarker));
parcel.setDataPosition(pin);
return false;
}
// Scan the records to collect metadata ids and offsets.
if (!scanAllRecords(parcel, size - kMetaHeaderSize)) {
parcel.setDataPosition(pin);
return false;
}
mParcel = parcel;
return true;
|
private boolean | scanAllRecords(android.os.Parcel parcel, int bytesLeft)Go over all the records, collecting metadata keys and records'
type field offset in the Parcel. These are stored in
mKeyToPosMap for latter retrieval.
Format of a metadata record:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| record size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| metadata key | // TITLE
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| metadata type | // STRING_VAL
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| .... metadata payload .... |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
int recCount = 0;
boolean error = false;
mKeyToPosMap.clear();
while (bytesLeft > kRecordHeaderSize) {
final int start = parcel.dataPosition();
// Check the size.
final int size = parcel.readInt();
if (size <= kRecordHeaderSize) { // at least 1 byte should be present.
Log.e(TAG, "Record is too short");
error = true;
break;
}
// Check the metadata key.
final int metadataId = parcel.readInt();
if (!checkMetadataId(metadataId)) {
error = true;
break;
}
// Store the record offset which points to the type
// field so we can later on read/unmarshall the record
// payload.
if (mKeyToPosMap.containsKey(metadataId)) {
Log.e(TAG, "Duplicate metadata ID found");
error = true;
break;
}
mKeyToPosMap.put(metadataId, parcel.dataPosition());
// Check the metadata type.
final int metadataType = parcel.readInt();
if (metadataType <= 0 || metadataType > LAST_TYPE) {
Log.e(TAG, "Invalid metadata type " + metadataType);
error = true;
break;
}
// Skip to the next one.
parcel.setDataPosition(start + size);
bytesLeft -= size;
++recCount;
}
if (0 != bytesLeft || error) {
Log.e(TAG, "Ran out of data or error on record " + recCount);
mKeyToPosMap.clear();
return false;
} else {
return true;
}
|