2 * DesfireFileSettings.java
4 * Copyright (C) 2011 Eric Butler
7 * Eric Butler <eric@codebutler.com>
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 package com.codebutler.farebot.card.desfire;
25 import java.io.ByteArrayInputStream;
27 import org.apache.commons.lang3.ArrayUtils;
29 import android.os.Parcel;
30 import android.os.Parcelable;
32 import com.codebutler.farebot.Utils;
34 public abstract class DesfireFileSettings implements Parcelable {
35 public final byte fileType;
36 public final byte commSetting;
37 public final byte[] accessRights;
39 /* DesfireFile Types */
40 static final byte STANDARD_DATA_FILE = (byte) 0x00;
41 static final byte BACKUP_DATA_FILE = (byte) 0x01;
42 static final byte VALUE_FILE = (byte) 0x02;
43 static final byte LINEAR_RECORD_FILE = (byte) 0x03;
44 static final byte CYCLIC_RECORD_FILE = (byte) 0x04;
46 public static DesfireFileSettings Create (byte[] data) throws DesfireException {
47 byte fileType = (byte) data[0];
49 ByteArrayInputStream stream = new ByteArrayInputStream(data);
51 if (fileType == STANDARD_DATA_FILE || fileType == BACKUP_DATA_FILE)
52 return new StandardDesfireFileSettings(stream);
53 else if (fileType == LINEAR_RECORD_FILE || fileType == CYCLIC_RECORD_FILE)
54 return new RecordDesfireFileSettings(stream);
55 else if (fileType == VALUE_FILE)
56 return new ValueDesfireFileSettings(stream);
58 throw new DesfireException("Unknown file type: " + Integer.toHexString(fileType));
61 private DesfireFileSettings (ByteArrayInputStream stream) {
62 fileType = (byte) stream.read();
63 commSetting = (byte) stream.read();
65 accessRights = new byte[2];
66 stream.read(accessRights, 0, accessRights.length);
69 private DesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights) {
70 this.fileType = fileType;
71 this.commSetting = commSetting;
72 this.accessRights = accessRights;
75 public String getFileTypeName () {
77 case STANDARD_DATA_FILE:
79 case BACKUP_DATA_FILE:
83 case LINEAR_RECORD_FILE:
84 return "Linear Record";
85 case CYCLIC_RECORD_FILE:
86 return "Cyclic Record";
92 public static final Parcelable.Creator<DesfireFileSettings> CREATOR = new Parcelable.Creator<DesfireFileSettings>() {
93 public DesfireFileSettings createFromParcel(Parcel source) {
94 byte fileType = source.readByte();
95 byte commSetting = source.readByte();
96 byte[] accessRights = new byte[source.readInt()];
97 source.readByteArray(accessRights);
99 if (fileType == STANDARD_DATA_FILE || fileType == BACKUP_DATA_FILE) {
100 int fileSize = source.readInt();
101 return new StandardDesfireFileSettings(fileType, commSetting, accessRights, fileSize);
102 } else if (fileType == LINEAR_RECORD_FILE || fileType == CYCLIC_RECORD_FILE) {
103 int recordSize = source.readInt();
104 int maxRecords = source.readInt();
105 int curRecords = source.readInt();
106 return new RecordDesfireFileSettings(fileType, commSetting, accessRights, recordSize, maxRecords, curRecords);
108 return new UnsupportedDesfireFileSettings(fileType);
112 public DesfireFileSettings[] newArray(int size) {
113 return new DesfireFileSettings[size];
117 public void writeToParcel (Parcel parcel, int flags) {
118 parcel.writeByte(fileType);
119 parcel.writeByte(commSetting);
120 parcel.writeInt(accessRights.length);
121 parcel.writeByteArray(accessRights);
124 public int describeContents () {
128 public static class StandardDesfireFileSettings extends DesfireFileSettings {
129 public final int fileSize;
131 private StandardDesfireFileSettings (ByteArrayInputStream stream) {
133 byte[] buf = new byte[3];
134 stream.read(buf, 0, buf.length);
135 ArrayUtils.reverse(buf);
136 fileSize = Utils.byteArrayToInt(buf);
139 StandardDesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights, int fileSize) {
140 super(fileType, commSetting, accessRights);
141 this.fileSize = fileSize;
145 public void writeToParcel (Parcel parcel, int flags) {
146 super.writeToParcel(parcel, flags);
147 parcel.writeInt(fileSize);
151 public static class RecordDesfireFileSettings extends DesfireFileSettings {
152 public final int recordSize;
153 public final int maxRecords;
154 public final int curRecords;
156 public RecordDesfireFileSettings(ByteArrayInputStream stream) {
159 byte[] buf = new byte[3];
160 stream.read(buf, 0, buf.length);
161 ArrayUtils.reverse(buf);
162 recordSize = Utils.byteArrayToInt(buf);
165 stream.read(buf, 0, buf.length);
166 ArrayUtils.reverse(buf);
167 maxRecords = Utils.byteArrayToInt(buf);
170 stream.read(buf, 0, buf.length);
171 ArrayUtils.reverse(buf);
172 curRecords = Utils.byteArrayToInt(buf);
175 RecordDesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights, int recordSize, int maxRecords, int curRecords) {
176 super(fileType, commSetting, accessRights);
177 this.recordSize = recordSize;
178 this.maxRecords = maxRecords;
179 this.curRecords = curRecords;
183 public void writeToParcel (Parcel parcel, int flags) {
184 super.writeToParcel(parcel, flags);
185 parcel.writeInt(recordSize);
186 parcel.writeInt(maxRecords);
187 parcel.writeInt(curRecords);
194 public static class ValueDesfireFileSettings extends DesfireFileSettings {
195 public final int lowerLimit;
196 public final int upperLimit;
197 public final int value;
198 public final byte limitedCreditEnabled;
200 public ValueDesfireFileSettings(ByteArrayInputStream stream) {
203 byte[] buf = new byte[4];
204 stream.read(buf, 0, buf.length);
205 ArrayUtils.reverse(buf);
206 lowerLimit = Utils.byteArrayToInt(buf);
209 stream.read(buf, 0, buf.length);
210 ArrayUtils.reverse(buf);
211 upperLimit = Utils.byteArrayToInt(buf);
214 stream.read(buf, 0, buf.length);
215 ArrayUtils.reverse(buf);
216 value = Utils.byteArrayToInt(buf);
220 stream.read(buf, 0, buf.length);
221 limitedCreditEnabled = buf[0];
223 //http://www.skyetek.com/docs/m2/desfire.pdf
224 //http://neteril.org/files/M075031_desfire.pdf
228 public void writeToParcel (Parcel parcel, int flags) {
229 super.writeToParcel(parcel, flags);
230 parcel.writeInt(lowerLimit);
231 parcel.writeInt(upperLimit);
232 parcel.writeInt(value);
233 parcel.writeByte(limitedCreditEnabled);
236 public static class UnsupportedDesfireFileSettings extends DesfireFileSettings {
237 public UnsupportedDesfireFileSettings(byte fileType) {
238 super(fileType, Byte.MIN_VALUE, new byte[0]);