Browse Source

migrated all farebot code to kotlin

pull/31/head
Jannik 3 years ago
parent
commit
b4ed1ca927
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
  1. 268
      app/src/main/java/com/codebutler/farebot/Utils.java
  2. 226
      app/src/main/java/com/codebutler/farebot/Utils.kt
  3. 77
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireApplication.java
  4. 13
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.java
  5. 9
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.kt
  6. 135
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.java
  7. 103
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.kt
  8. 241
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.java
  9. 247
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.kt
  10. 173
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.java
  11. 180
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.kt
  12. 188
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.java
  13. 213
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.kt
  14. 14
      app/src/main/java/com/codebutler/farebot/card/desfire/DesfireRecord.kt

268
app/src/main/java/com/codebutler/farebot/Utils.java

@ -1,268 +0,0 @@
/*
* Utils.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;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.util.Log;
import android.view.WindowManager;
import com.codebutler.farebot.card.desfire.DesfireException;
import com.codebutler.farebot.card.desfire.DesfireFileSettings;
import com.codebutler.farebot.card.desfire.DesfireProtocol;
import org.w3c.dom.Node;
import java.io.StringWriter;
import java.util.List;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
public class Utils {
private static final String TAG = Utils.class.getName();
public static void showError (final Activity activity, Exception ex) {
Log.e(activity.getClass().getName(), ex.getMessage(), ex);
new AlertDialog.Builder(activity)
.setMessage(Utils.getErrorMessage(ex))
.show();
}
public static void showErrorAndFinish (final Activity activity, Exception ex) {
try {
Log.e(activity.getClass().getName(), Utils.getErrorMessage(ex));
ex.printStackTrace();
new AlertDialog.Builder(activity)
.setMessage(Utils.getErrorMessage(ex))
.setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
activity.finish();
}
})
.show();
} catch (WindowManager.BadTokenException unused) {
/* Ignore... happens if the activity was destroyed */
}
}
public static String getHexString (byte[] b) throws Exception {
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return result;
}
public static String getHexString (byte[] b, String defaultResult) {
try {
return getHexString(b);
} catch (Exception ex) {
return defaultResult;
}
}
public static byte[] hexStringToByteArray (String s) {
if ((s.length() % 2) != 0) {
throw new IllegalArgumentException("Bad input string: " + s);
}
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
/*
public static byte[] intToByteArray(int value) {
return new byte[] {
(byte)(value >>> 24),
(byte)(value >>> 16),
(byte)(value >>> 8),
(byte)value};
}
*/
public static int byteArrayToInt(byte[] b) {
return byteArrayToInt(b, 0);
}
public static int byteArrayToInt(byte[] b, int offset) {
return byteArrayToInt(b, offset, b.length);
}
public static int byteArrayToInt(byte[] b, int offset, int length) {
return (int) byteArrayToLong(b, offset, length);
}
public static long byteArrayToLong(byte[] b, int offset, int length) {
if (b.length < length)
throw new IllegalArgumentException("length must be less than or equal to b.length");
long value = 0;
for (int i = 0; i < length; i++) {
int shift = (length - 1 - i) * 8;
value += (b[i + offset] & 0x000000FF) << shift;
}
return value;
}
public static byte[] byteArraySlice(byte[] b, int offset, int length) {
byte[] ret = new byte[length];
for (int i = 0; i < length; i++)
ret[i] = b[offset+i];
return ret;
}
public static String xmlNodeToString (Node node) throws Exception {
// The amount of code required to do simple things in Java is incredible.
Source source = new DOMSource(node);
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.setURIResolver(null);
transformer.transform(source, result);
return stringWriter.getBuffer().toString();
}
public static String getErrorMessage (Throwable ex) {
String errorMessage = ex.getLocalizedMessage();
if (errorMessage == null)
errorMessage = ex.getMessage();
if (errorMessage == null)
errorMessage = ex.toString();
if (ex.getCause() != null) {
String causeMessage = ex.getCause().getLocalizedMessage();
if (causeMessage == null)
causeMessage = ex.getCause().getMessage();
if (causeMessage == null)
causeMessage = ex.getCause().toString();
if (causeMessage != null)
errorMessage += ": " + causeMessage;
}
return errorMessage;
}
public static <T> T findInList(List<T> list, Matcher<T> matcher) {
for (T item : list) {
if (matcher.matches(item)) {
return item;
}
}
return null;
}
public static interface Matcher<T> {
public boolean matches(T t);
}
public static int convertBCDtoInteger(byte data) {
return (((data & (char)0xF0) >> 4) * 10) + ((data & (char)0x0F));
}
public static int getBitsFromInteger(int buffer, int iStartBit, int iLength) {
return (buffer >> (iStartBit)) & ((char)0xFF >> (8 - iLength));
}
/* Based on function from mfocGUI by 'Huuf' (http://www.huuf.info/OV/) */
public static int getBitsFromBuffer(byte[] buffer, int iStartBit, int iLength) {
int iEndBit = iStartBit + iLength - 1;
int iSByte = iStartBit / 8;
int iSBit = iStartBit % 8;
int iEByte = iEndBit / 8;
int iEBit = iEndBit % 8;
if (iSByte == iEByte) {
return (int)(((char)buffer[iEByte] >> (7 - iEBit)) & ((char)0xFF >> (8 - iLength)));
} else {
int uRet = (((char)buffer[iSByte] & (char)((char)0xFF >> iSBit)) << (((iEByte - iSByte - 1) * 8) + (iEBit + 1)));
for (int i = iSByte + 1; i < iEByte; i++) {
uRet |= (((char)buffer[i] & (char)0xFF) << (((iEByte - i - 1) * 8) + (iEBit + 1)));
}
uRet |= (((char)buffer[iEByte] & (char)0xFF)) >> (7 - iEBit);
return uRet;
}
}
public static DesfireFileSettings selectAppFile(DesfireProtocol tag, int appID, int fileID) {
try {
tag.selectApp(appID);
} catch (DesfireException e) {
Log.w(TAG,"App not found");
return null;
}
try {
return tag.getFileSettings(fileID);
} catch (DesfireException e) {
Log.w(TAG,"File not found");
return null;
}
}
public static boolean arrayContains(int[] arr, int item) {
for (int i: arr)
if (i==item)
return true;
return false;
}
public static boolean containsAppFile(DesfireProtocol tag, int appID, int fileID) {
try {
tag.selectApp(appID);
} catch (DesfireException e) {
Log.w(TAG,"App not found");
Log.w(TAG, e);
return false;
}
try {
return arrayContains(tag.getFileList(),fileID);
} catch (DesfireException e) {
Log.w(TAG,"File not found");
Log.w(TAG, e);
return false;
}
}
}

226
app/src/main/java/com/codebutler/farebot/Utils.kt

@ -0,0 +1,226 @@
/*
* Utils.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
import android.app.Activity
import android.app.AlertDialog
import android.util.Log
import android.view.WindowManager
import com.codebutler.farebot.card.desfire.DesfireException
import com.codebutler.farebot.card.desfire.DesfireFileSettings
import com.codebutler.farebot.card.desfire.DesfireProtocol
import org.w3c.dom.Node
import java.io.StringWriter
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
import kotlin.experimental.and
class Utils {
companion object {
private val TAG = Utils::class.java.name
@Suppress("unused")
fun showError(activity: Activity, ex: Exception) {
Log.e(activity.javaClass.name, ex.message, ex)
AlertDialog.Builder(activity)
.setMessage(getErrorMessage(ex))
.show()
}
@Suppress("unused")
fun showErrorAndFinish(activity: Activity, ex: Exception) {
try {
Log.e(activity.javaClass.name, getErrorMessage(ex))
ex.printStackTrace()
AlertDialog.Builder(activity)
.setMessage(getErrorMessage(ex))
.setCancelable(false)
.setPositiveButton(android.R.string.ok) { _, _ -> activity.finish() }
.show()
} catch (unused: WindowManager.BadTokenException) {
/* Ignore... happens if the activity was destroyed */
}
}
@Throws(Exception::class)
fun getHexString(b: ByteArray): String {
var result = ""
for (i in b.indices) {
result += ((b[i] and 0xff.toByte()) + 0x100).toString(16).substring(1)
}
return result
}
@Suppress("unused")
fun getHexString(b: ByteArray, defaultResult: String): String {
return try {
getHexString(b)
} catch (ex: Exception) {
defaultResult
}
}
@Suppress("unused")
fun hexStringToByteArray(s: String): ByteArray {
if (s.length % 2 != 0) {
throw IllegalArgumentException("Bad input string: $s")
}
val len = s.length
val data = ByteArray(len / 2)
var i = 0
while (i < len) {
data[i / 2] = ((Character.digit(s[i], 16) shl 4) + Character.digit(s[i + 1], 16)).toByte()
i += 2
}
return data
}
@JvmOverloads
fun byteArrayToInt(b: ByteArray, offset: Int = 0, length: Int = b.size): Int {
return byteArrayToLong(b, offset, length).toInt()
}
fun byteArrayToLong(b: ByteArray, offset: Int, length: Int): Long {
if (b.size < length)
throw IllegalArgumentException("length must be less than or equal to b.length")
var value: Long = 0
for (i in 0 until length) {
val shift = (length - 1 - i) * 8
value += ((b[i + offset].toInt() and 0x000000FF).toLong() shl shift)
}
return value
}
@Suppress("unused")
fun byteArraySlice(b: ByteArray, offset: Int, length: Int): ByteArray {
val ret = ByteArray(length)
for (i in 0 until length)
ret[i] = b[offset + i]
return ret
}
@Suppress("unused")
@Throws(Exception::class)
fun xmlNodeToString(node: Node): String {
// The amount of code required to do simple things in Java is incredible.
val source = DOMSource(node)
val stringWriter = StringWriter()
val result = StreamResult(stringWriter)
val factory = TransformerFactory.newInstance()
val transformer = factory.newTransformer()
transformer.setOutputProperty(OutputKeys.INDENT, "yes")
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
transformer.uriResolver = null
transformer.transform(source, result)
return stringWriter.buffer.toString()
}
fun getErrorMessage(ex: Throwable): String {
var errorMessage: String? = ex.localizedMessage
if (errorMessage == null)
errorMessage = ex.message
if (errorMessage == null)
errorMessage = ex.toString()
if (ex.cause != null) {
var causeMessage: String? = ex.cause!!.localizedMessage
if (causeMessage == null)
causeMessage = ex.cause!!.message
if (causeMessage == null)
causeMessage = ex.cause.toString()
errorMessage += ": $causeMessage"
}
return errorMessage
}
@Suppress("unused")
fun <T> findInList(list: List<T>, matcher: Matcher<T>): T? {
for (item in list) {
if (matcher.matches(item)) {
return item
}
}
return null
}
interface Matcher<T> {
fun matches(t: T): Boolean
}
fun selectAppFile(tag: DesfireProtocol, appID: Int, fileID: Int): DesfireFileSettings? {
try {
tag.selectApp(appID)
} catch (e: DesfireException) {
Log.w(TAG, "App not found")
return null
}
return try {
tag.getFileSettings(fileID)
} catch (e: DesfireException) {
Log.w(TAG, "File not found")
null
}
}
fun arrayContains(arr: IntArray, item: Int): Boolean {
for (i in arr)
if (i == item)
return true
return false
}
@Suppress("unused")
fun containsAppFile(tag: DesfireProtocol, appID: Int, fileID: Int): Boolean {
try {
tag.selectApp(appID)
} catch (e: DesfireException) {
Log.w(TAG, "App not found")
Log.w(TAG, e)
return false
}
return try {
arrayContains(tag.fileList, fileID)
} catch (e: DesfireException) {
Log.w(TAG, "File not found")
Log.w(TAG, e)
false
}
}
}
}

77
app/src/main/java/com/codebutler/farebot/card/desfire/DesfireApplication.java

@ -1,77 +0,0 @@
/*
* DesfireApplication.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 android.os.Parcel;
import android.os.Parcelable;
public class DesfireApplication implements Parcelable {
private int mId;
private DesfireFile[] mFiles;
public DesfireApplication (int id, DesfireFile[] files) {
mId = id;
mFiles = files;
}
public int getId () {
return mId;
}
public DesfireFile[] getFiles () {
return mFiles;
}
public DesfireFile getFile (int fileId) {
for (DesfireFile file : mFiles) {
if (file.getId() == fileId)
return file;
}
return null;
}
public static final Parcelable.Creator<DesfireApplication> CREATOR = new Parcelable.Creator<DesfireApplication>() {
public DesfireApplication createFromParcel(Parcel source) {
int id = source.readInt();
DesfireFile[] files = new DesfireFile[source.readInt()];
source.readTypedArray(files, DesfireFile.CREATOR);
return new DesfireApplication(id, files);
}
public DesfireApplication[] newArray (int size) {
return new DesfireApplication[size];
}
};
public void writeToParcel (Parcel parcel, int flags) {
parcel.writeInt(mId);
parcel.writeInt(mFiles.length);
parcel.writeTypedArray(mFiles, flags);
}
public int describeContents () {
return 0;
}
}

13
app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.java

@ -1,13 +0,0 @@
package com.codebutler.farebot.card.desfire;
/**
* Created by Jakob Wenzel on 16.11.13.
*/
public class DesfireException extends Exception {
public DesfireException(String message) {
super(message);
}
public DesfireException(Throwable cause) {
super(cause);
}
}

9
app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.kt

@ -0,0 +1,9 @@
package com.codebutler.farebot.card.desfire
/**
* Created by Jakob Wenzel on 16.11.13.
*/
class DesfireException : Exception {
constructor(message: String) : super(message) {}
constructor(cause: Throwable) : super(cause) {}
}

135
app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.java

@ -1,135 +0,0 @@
/*
* DesfireFile.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 org.apache.commons.lang3.ArrayUtils;
import android.os.Parcel;
import android.os.Parcelable;
import com.codebutler.farebot.card.desfire.DesfireFileSettings.RecordDesfireFileSettings;
public class DesfireFile implements Parcelable {
private int mId;
private DesfireFileSettings mSettings;
private byte[] mData;
public static DesfireFile create (int fileId, DesfireFileSettings fileSettings, byte[] fileData) {
if (fileSettings instanceof RecordDesfireFileSettings)
return new RecordDesfireFile(fileId, fileSettings, fileData);
else
return new DesfireFile(fileId, fileSettings, fileData);
}
private DesfireFile (int fileId, DesfireFileSettings fileSettings, byte[] fileData) {
mId = fileId;
mSettings = fileSettings;
mData = fileData;
}
public DesfireFileSettings getFileSettings () {
return mSettings;
}
public int getId () {
return mId;
}
public byte[] getData () {
return mData;
}
public static final Parcelable.Creator<DesfireFile> CREATOR = new Parcelable.Creator<DesfireFile>() {
public DesfireFile createFromParcel(Parcel source) {
int fileId = source.readInt();
boolean isError = (source.readInt() == 1);
if (!isError) {
DesfireFileSettings fileSettings = (DesfireFileSettings) source.readParcelable(DesfireFileSettings.class.getClassLoader());
int dataLength = source.readInt();
byte[] fileData = new byte[dataLength];
source.readByteArray(fileData);
return DesfireFile.create(fileId, fileSettings, fileData);
} else {
return new InvalidDesfireFile(fileId, source.readString());
}
}
public DesfireFile[] newArray (int size) {
return new DesfireFile[size];
}
};
public void writeToParcel (Parcel parcel, int flags) {
parcel.writeInt(mId);
if (this instanceof InvalidDesfireFile) {
parcel.writeInt(1);
parcel.writeString(((InvalidDesfireFile)this).getErrorMessage());
} else {
parcel.writeInt(0);
parcel.writeParcelable(mSettings, 0);
parcel.writeInt(mData.length);
parcel.writeByteArray(mData);
}
}
public int describeContents () {
return 0;
}
public static class RecordDesfireFile extends DesfireFile {
private DesfireRecord[] mRecords;
private RecordDesfireFile (int fileId, DesfireFileSettings fileSettings, byte[] fileData) {
super(fileId, fileSettings, fileData);
RecordDesfireFileSettings settings = (RecordDesfireFileSettings) fileSettings;
DesfireRecord[] records = new DesfireRecord[settings.curRecords];
for (int i = 0; i < settings.curRecords; i++) {
int offset = settings.recordSize * i;
records[i] = new DesfireRecord(ArrayUtils.subarray(getData(), offset, offset + settings.recordSize));
}
mRecords = records;
}
public DesfireRecord[] getRecords () {
return mRecords;
}
}
public static class InvalidDesfireFile extends DesfireFile {
private String mErrorMessage;
public InvalidDesfireFile (int fileId, String errorMessage) {
super(fileId, null, new byte[0]);
mErrorMessage = errorMessage;
}
public String getErrorMessage () {
return mErrorMessage;
}
}
}

103
app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.kt

@ -0,0 +1,103 @@
/**
* DesfireFile.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 android.os.Parcel
import android.os.Parcelable
import com.codebutler.farebot.card.desfire.DesfireFileSettings.RecordDesfireFileSettings
import org.apache.commons.lang3.ArrayUtils
open class DesfireFile private constructor(val id: Int, private val fileSettings: DesfireFileSettings?, val data: ByteArray) :
Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
if (this is InvalidDesfireFile) {
parcel.writeInt(1)
parcel.writeString(this.errorMessage)
} else {
parcel.writeInt(0)
parcel.writeParcelable(fileSettings, 0)
parcel.writeInt(data.size)
parcel.writeByteArray(data)
}
}
override fun describeContents(): Int {
return 0
}
class RecordDesfireFile(fileId: Int, fileSettings: DesfireFileSettings, fileData: ByteArray) :
DesfireFile(fileId, fileSettings, fileData) {
private val records: Array<DesfireRecord?>
init {
val settings = fileSettings as RecordDesfireFileSettings
val records = arrayOfNulls<DesfireRecord>(settings.curRecords)
for (i in 0 until settings.curRecords) {
val offset = settings.recordSize * i
records[i] = DesfireRecord(ArrayUtils.subarray(data, offset, offset + settings.recordSize))
}
this.records = records
}
}
class InvalidDesfireFile(fileId: Int, val errorMessage: String?) : DesfireFile(fileId, null, ByteArray(0))
companion object {
fun create(fileId: Int, fileSettings: DesfireFileSettings, fileData: ByteArray): DesfireFile {
return (fileSettings as? RecordDesfireFileSettings)?.let { RecordDesfireFile(fileId, it, fileData) }
?: DesfireFile(fileId, fileSettings, fileData)
}
@Suppress("unused")
@JvmField
val CREATOR: Parcelable.Creator<DesfireFile> = object : Parcelable.Creator<DesfireFile> {
override fun createFromParcel(source: Parcel): DesfireFile {
val fileId = source.readInt()
val isError = source.readInt() == 1
return if (!isError) {
val fileSettings =
source.readParcelable<Parcelable>(DesfireFileSettings::class.java.classLoader) as DesfireFileSettings
val dataLength = source.readInt()
val fileData = ByteArray(dataLength)
source.readByteArray(fileData)
create(fileId, fileSettings, fileData)
} else {
InvalidDesfireFile(fileId, source.readString())
}
}
override fun newArray(size: Int): Array<DesfireFile?> {
return arrayOfNulls(size)
}
}
}
}

241
app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.java

@ -1,241 +0,0 @@
/*
* 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]);
}
}
}

247
app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.kt

@ -0,0 +1,247 @@
/*
* 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 android.os.Parcel
import android.os.Parcelable
import com.codebutler.farebot.Utils
import org.apache.commons.lang3.ArrayUtils
import java.io.ByteArrayInputStream
abstract class DesfireFileSettings : Parcelable {
private val fileType: Byte
private val commSetting: Byte
private val accessRights: ByteArray
@Suppress("unused")
val fileTypeName: String
get() {
return when (fileType) {
STANDARD_DATA_FILE -> "Standard"
BACKUP_DATA_FILE -> "Backup"
VALUE_FILE -> "Value"
LINEAR_RECORD_FILE -> "Linear Record"
CYCLIC_RECORD_FILE -> "Cyclic Record"
else -> "Unknown"
}
}
private constructor(stream: ByteArrayInputStream) {
fileType = stream.read().toByte()
commSetting = stream.read().toByte()
accessRights = ByteArray(2)
stream.read(accessRights, 0, accessRights.size)
}
private constructor(fileType: Byte, commSetting: Byte, accessRights: ByteArray) {
this.fileType = fileType
this.commSetting = commSetting
this.accessRights = accessRights
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeByte(fileType)
parcel.writeByte(commSetting)
parcel.writeInt(accessRights.size)
parcel.writeByteArray(accessRights)
}
override fun describeContents(): Int {
return 0
}
class StandardDesfireFileSettings : DesfireFileSettings {
private val fileSize: Int
internal constructor(stream: ByteArrayInputStream) : super(stream) {
val buf = ByteArray(3)
stream.read(buf, 0, buf.size)
ArrayUtils.reverse(buf)
fileSize = Utils.byteArrayToInt(buf)
}
internal constructor(
fileType: Byte,
commSetting: Byte,
accessRights: ByteArray,
fileSize: Int
) : super(fileType, commSetting, accessRights) {
this.fileSize = fileSize
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
super.writeToParcel(parcel, flags)
parcel.writeInt(fileSize)
}
}
class RecordDesfireFileSettings : DesfireFileSettings {
private val maxRecords: Int
val recordSize: Int
val curRecords: Int
constructor(stream: ByteArrayInputStream) : super(stream) {
var buf = ByteArray(3)
stream.read(buf, 0, buf.size)
ArrayUtils.reverse(buf)
recordSize = Utils.byteArrayToInt(buf)
buf = ByteArray(3)
stream.read(buf, 0, buf.size)
ArrayUtils.reverse(buf)
maxRecords = Utils.byteArrayToInt(buf)
buf = ByteArray(3)
stream.read(buf, 0, buf.size)
ArrayUtils.reverse(buf)
curRecords = Utils.byteArrayToInt(buf)
}
internal constructor(
fileType: Byte,
commSetting: Byte,
accessRights: ByteArray,
recordSize: Int,
maxRecords: Int,
curRecords: Int
) : super(fileType, commSetting, accessRights) {
this.recordSize = recordSize
this.maxRecords = maxRecords
this.curRecords = curRecords
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
super.writeToParcel(parcel, flags)
parcel.writeInt(recordSize)
parcel.writeInt(maxRecords)
parcel.writeInt(curRecords)
}
}
class ValueDesfireFileSettings(stream: ByteArrayInputStream) : DesfireFileSettings(stream) {
private val lowerLimit: Int
private val upperLimit: Int
val value: Int
private val limitedCreditEnabled: Byte
init {
var buf = ByteArray(4)
stream.read(buf, 0, buf.size)
ArrayUtils.reverse(buf)
lowerLimit = Utils.byteArrayToInt(buf)
buf = ByteArray(4)
stream.read(buf, 0, buf.size)
ArrayUtils.reverse(buf)
upperLimit = Utils.byteArrayToInt(buf)
buf = ByteArray(4)
stream.read(buf, 0, buf.size)
ArrayUtils.reverse(buf)
value = Utils.byteArrayToInt(buf)
buf = ByteArray(1)
stream.read(buf, 0, buf.size)
limitedCreditEnabled = buf[0]
//http://www.skyetek.com/docs/m2/desfire.pdf
//http://neteril.org/files/M075031_desfire.pdf
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
super.writeToParcel(parcel, flags)
parcel.writeInt(lowerLimit)
parcel.writeInt(upperLimit)
parcel.writeInt(value)
parcel.writeByte(limitedCreditEnabled)
}
}
class UnsupportedDesfireFileSettings(fileType: Byte) :
DesfireFileSettings(fileType, java.lang.Byte.MIN_VALUE, ByteArray(0))
companion object {
/* DesfireFile Types */
internal const val STANDARD_DATA_FILE = 0x00.toByte()
internal const val BACKUP_DATA_FILE = 0x01.toByte()
internal const val VALUE_FILE = 0x02.toByte()
internal const val LINEAR_RECORD_FILE = 0x03.toByte()
internal const val CYCLIC_RECORD_FILE = 0x04.toByte()
@Throws(DesfireException::class)
fun create(data: ByteArray): DesfireFileSettings {
val fileType = data[0]
val stream = ByteArrayInputStream(data)
return if (fileType == STANDARD_DATA_FILE || fileType == BACKUP_DATA_FILE)
StandardDesfireFileSettings(stream)
else if (fileType == LINEAR_RECORD_FILE || fileType == CYCLIC_RECORD_FILE)
RecordDesfireFileSettings(stream)
else if (fileType == VALUE_FILE)
ValueDesfireFileSettings(stream)
else
throw DesfireException("Unknown file type: " + Integer.toHexString(fileType.toInt()))
}
@Suppress("unused")
@JvmField
val CREATOR: Parcelable.Creator<DesfireFileSettings> = object : Parcelable.Creator<DesfireFileSettings> {
override fun createFromParcel(source: Parcel): DesfireFileSettings {
val fileType = source.readByte()
val commSetting = source.readByte()
val accessRights = ByteArray(source.readInt())
source.readByteArray(accessRights)
if (fileType == STANDARD_DATA_FILE || fileType == BACKUP_DATA_FILE) {
val fileSize = source.readInt()
return StandardDesfireFileSettings(fileType, commSetting, accessRights, fileSize)
} else if (fileType == LINEAR_RECORD_FILE || fileType == CYCLIC_RECORD_FILE) {
val recordSize = source.readInt()
val maxRecords = source.readInt()
val curRecords = source.readInt()
return RecordDesfireFileSettings(
fileType,
commSetting,
accessRights,
recordSize,
maxRecords,
curRecords
)
} else {
return UnsupportedDesfireFileSettings(fileType)
}
}
override fun newArray(size: Int): Array<DesfireFileSettings?> {
return arrayOfNulls(size)
}
}
}
}

173
app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.java

@ -1,173 +0,0 @@
/*
* DesfireManufacturingData.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 android.os.Parcel;
import android.os.Parcelable;
import com.codebutler.farebot.Utils;
import org.w3c.dom.Element;
import java.io.ByteArrayInputStream;
public class DesfireManufacturingData implements Parcelable {
public final int hwVendorID;
public final int hwType;
public final int hwSubType;
public final int hwMajorVersion;
public final int hwMinorVersion;
public final int hwStorageSize;
public final int hwProtocol;
public final int swVendorID;
public final int swType;
public final int swSubType;
public final int swMajorVersion;