241 lines
8.3 KiB
Java
241 lines
8.3 KiB
Java
/*
|
|
* DesfireFileSettings.java
|
|
*
|
|
* Copyright (C) 2011 Eric Butler
|
|
*
|
|
* Authors:
|
|
* Eric Butler <eric@codebutler.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package com.codebutler.farebot.card.desfire;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
|
import org.apache.commons.lang3.ArrayUtils;
|
|
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
|
|
import com.codebutler.farebot.Utils;
|
|
|
|
public abstract class DesfireFileSettings implements Parcelable {
|
|
public final byte fileType;
|
|
public final byte commSetting;
|
|
public final byte[] accessRights;
|
|
|
|
/* DesfireFile Types */
|
|
static final byte STANDARD_DATA_FILE = (byte) 0x00;
|
|
static final byte BACKUP_DATA_FILE = (byte) 0x01;
|
|
static final byte VALUE_FILE = (byte) 0x02;
|
|
static final byte LINEAR_RECORD_FILE = (byte) 0x03;
|
|
static final byte CYCLIC_RECORD_FILE = (byte) 0x04;
|
|
|
|
public static DesfireFileSettings Create (byte[] data) throws DesfireException {
|
|
byte fileType = (byte) data[0];
|
|
|
|
ByteArrayInputStream stream = new ByteArrayInputStream(data);
|
|
|
|
if (fileType == STANDARD_DATA_FILE || fileType == BACKUP_DATA_FILE)
|
|
return new StandardDesfireFileSettings(stream);
|
|
else if (fileType == LINEAR_RECORD_FILE || fileType == CYCLIC_RECORD_FILE)
|
|
return new RecordDesfireFileSettings(stream);
|
|
else if (fileType == VALUE_FILE)
|
|
return new ValueDesfireFileSettings(stream);
|
|
else
|
|
throw new DesfireException("Unknown file type: " + Integer.toHexString(fileType));
|
|
}
|
|
|
|
private DesfireFileSettings (ByteArrayInputStream stream) {
|
|
fileType = (byte) stream.read();
|
|
commSetting = (byte) stream.read();
|
|
|
|
accessRights = new byte[2];
|
|
stream.read(accessRights, 0, accessRights.length);
|
|
}
|
|
|
|
private DesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights) {
|
|
this.fileType = fileType;
|
|
this.commSetting = commSetting;
|
|
this.accessRights = accessRights;
|
|
}
|
|
|
|
public String getFileTypeName () {
|
|
switch (fileType) {
|
|
case STANDARD_DATA_FILE:
|
|
return "Standard";
|
|
case BACKUP_DATA_FILE:
|
|
return "Backup";
|
|
case VALUE_FILE:
|
|
return "Value";
|
|
case LINEAR_RECORD_FILE:
|
|
return "Linear Record";
|
|
case CYCLIC_RECORD_FILE:
|
|
return "Cyclic Record";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
public static final Parcelable.Creator<DesfireFileSettings> CREATOR = new Parcelable.Creator<DesfireFileSettings>() {
|
|
public DesfireFileSettings createFromParcel(Parcel source) {
|
|
byte fileType = source.readByte();
|
|
byte commSetting = source.readByte();
|
|
byte[] accessRights = new byte[source.readInt()];
|
|
source.readByteArray(accessRights);
|
|
|
|
if (fileType == STANDARD_DATA_FILE || fileType == BACKUP_DATA_FILE) {
|
|
int fileSize = source.readInt();
|
|
return new StandardDesfireFileSettings(fileType, commSetting, accessRights, fileSize);
|
|
} else if (fileType == LINEAR_RECORD_FILE || fileType == CYCLIC_RECORD_FILE) {
|
|
int recordSize = source.readInt();
|
|
int maxRecords = source.readInt();
|
|
int curRecords = source.readInt();
|
|
return new RecordDesfireFileSettings(fileType, commSetting, accessRights, recordSize, maxRecords, curRecords);
|
|
} else {
|
|
return new UnsupportedDesfireFileSettings(fileType);
|
|
}
|
|
}
|
|
|
|
public DesfireFileSettings[] newArray(int size) {
|
|
return new DesfireFileSettings[size];
|
|
}
|
|
};
|
|
|
|
public void writeToParcel (Parcel parcel, int flags) {
|
|
parcel.writeByte(fileType);
|
|
parcel.writeByte(commSetting);
|
|
parcel.writeInt(accessRights.length);
|
|
parcel.writeByteArray(accessRights);
|
|
}
|
|
|
|
public int describeContents () {
|
|
return 0;
|
|
}
|
|
|
|
public static class StandardDesfireFileSettings extends DesfireFileSettings {
|
|
public final int fileSize;
|
|
|
|
private StandardDesfireFileSettings (ByteArrayInputStream stream) {
|
|
super(stream);
|
|
byte[] buf = new byte[3];
|
|
stream.read(buf, 0, buf.length);
|
|
ArrayUtils.reverse(buf);
|
|
fileSize = Utils.byteArrayToInt(buf);
|
|
}
|
|
|
|
StandardDesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights, int fileSize) {
|
|
super(fileType, commSetting, accessRights);
|
|
this.fileSize = fileSize;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel (Parcel parcel, int flags) {
|
|
super.writeToParcel(parcel, flags);
|
|
parcel.writeInt(fileSize);
|
|
}
|
|
}
|
|
|
|
public static class RecordDesfireFileSettings extends DesfireFileSettings {
|
|
public final int recordSize;
|
|
public final int maxRecords;
|
|
public final int curRecords;
|
|
|
|
public RecordDesfireFileSettings(ByteArrayInputStream stream) {
|
|
super(stream);
|
|
|
|
byte[] buf = new byte[3];
|
|
stream.read(buf, 0, buf.length);
|
|
ArrayUtils.reverse(buf);
|
|
recordSize = Utils.byteArrayToInt(buf);
|
|
|
|
buf = new byte[3];
|
|
stream.read(buf, 0, buf.length);
|
|
ArrayUtils.reverse(buf);
|
|
maxRecords = Utils.byteArrayToInt(buf);
|
|
|
|
buf = new byte[3];
|
|
stream.read(buf, 0, buf.length);
|
|
ArrayUtils.reverse(buf);
|
|
curRecords = Utils.byteArrayToInt(buf);
|
|
}
|
|
|
|
RecordDesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights, int recordSize, int maxRecords, int curRecords) {
|
|
super(fileType, commSetting, accessRights);
|
|
this.recordSize = recordSize;
|
|
this.maxRecords = maxRecords;
|
|
this.curRecords = curRecords;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel (Parcel parcel, int flags) {
|
|
super.writeToParcel(parcel, flags);
|
|
parcel.writeInt(recordSize);
|
|
parcel.writeInt(maxRecords);
|
|
parcel.writeInt(curRecords);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class ValueDesfireFileSettings extends DesfireFileSettings {
|
|
public final int lowerLimit;
|
|
public final int upperLimit;
|
|
public final int value;
|
|
public final byte limitedCreditEnabled;
|
|
|
|
public ValueDesfireFileSettings(ByteArrayInputStream stream) {
|
|
super(stream);
|
|
|
|
byte[] buf = new byte[4];
|
|
stream.read(buf, 0, buf.length);
|
|
ArrayUtils.reverse(buf);
|
|
lowerLimit = Utils.byteArrayToInt(buf);
|
|
|
|
buf = new byte[4];
|
|
stream.read(buf, 0, buf.length);
|
|
ArrayUtils.reverse(buf);
|
|
upperLimit = Utils.byteArrayToInt(buf);
|
|
|
|
buf = new byte[4];
|
|
stream.read(buf, 0, buf.length);
|
|
ArrayUtils.reverse(buf);
|
|
value = Utils.byteArrayToInt(buf);
|
|
|
|
|
|
buf = new byte[1];
|
|
stream.read(buf, 0, buf.length);
|
|
limitedCreditEnabled = buf[0];
|
|
|
|
//http://www.skyetek.com/docs/m2/desfire.pdf
|
|
//http://neteril.org/files/M075031_desfire.pdf
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel (Parcel parcel, int flags) {
|
|
super.writeToParcel(parcel, flags);
|
|
parcel.writeInt(lowerLimit);
|
|
parcel.writeInt(upperLimit);
|
|
parcel.writeInt(value);
|
|
parcel.writeByte(limitedCreditEnabled);
|
|
}
|
|
}
|
|
public static class UnsupportedDesfireFileSettings extends DesfireFileSettings {
|
|
public UnsupportedDesfireFileSettings(byte fileType) {
|
|
super(fileType, Byte.MIN_VALUE, new byte[0]);
|
|
}
|
|
}
|
|
} |