From b4ed1ca9271e13e5449b238811453164d49642d7 Mon Sep 17 00:00:00 2001 From: Seil0 Date: Mon, 19 Aug 2019 12:42:56 +0200 Subject: [PATCH] migrated all farebot code to kotlin --- .../java/com/codebutler/farebot/Utils.java | 268 ------------------ .../main/java/com/codebutler/farebot/Utils.kt | 226 +++++++++++++++ .../card/desfire/DesfireApplication.java | 77 ----- .../card/desfire/DesfireException.java | 13 - .../farebot/card/desfire/DesfireException.kt | 9 + .../farebot/card/desfire/DesfireFile.java | 135 --------- .../farebot/card/desfire/DesfireFile.kt | 103 +++++++ .../card/desfire/DesfireFileSettings.java | 241 ---------------- .../card/desfire/DesfireFileSettings.kt | 247 ++++++++++++++++ .../desfire/DesfireManufacturingData.java | 173 ----------- .../card/desfire/DesfireManufacturingData.kt | 180 ++++++++++++ .../farebot/card/desfire/DesfireProtocol.java | 188 ------------ .../farebot/card/desfire/DesfireProtocol.kt | 213 ++++++++++++++ .../{DesfireRecord.java => DesfireRecord.kt} | 14 +- 14 files changed, 980 insertions(+), 1107 deletions(-) delete mode 100644 app/src/main/java/com/codebutler/farebot/Utils.java create mode 100644 app/src/main/java/com/codebutler/farebot/Utils.kt delete mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireApplication.java delete mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.java create mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.kt delete mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.java create mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.kt delete mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.java create mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.kt delete mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.java create mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.kt delete mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.java create mode 100644 app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.kt rename app/src/main/java/com/codebutler/farebot/card/desfire/{DesfireRecord.java => DesfireRecord.kt} (76%) diff --git a/app/src/main/java/com/codebutler/farebot/Utils.java b/app/src/main/java/com/codebutler/farebot/Utils.java deleted file mode 100644 index c77b93c..0000000 --- a/app/src/main/java/com/codebutler/farebot/Utils.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Utils.java - * - * Copyright (C) 2011 Eric Butler - * - * Authors: - * Eric Butler - * - * 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 . - */ - -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 findInList(List list, Matcher matcher) { - for (T item : list) { - if (matcher.matches(item)) { - return item; - } - } - return null; - } - - public static interface Matcher { - 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; - } - } -} diff --git a/app/src/main/java/com/codebutler/farebot/Utils.kt b/app/src/main/java/com/codebutler/farebot/Utils.kt new file mode 100644 index 0000000..f8c721b --- /dev/null +++ b/app/src/main/java/com/codebutler/farebot/Utils.kt @@ -0,0 +1,226 @@ +/* + * Utils.java + * + * Copyright (C) 2011 Eric Butler + * + * Authors: + * Eric Butler + * + * 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 . + */ + +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 findInList(list: List, matcher: Matcher): T? { + for (item in list) { + if (matcher.matches(item)) { + return item + } + } + return null + } + + interface Matcher { + 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 + } + + } + } + +} diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireApplication.java b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireApplication.java deleted file mode 100644 index bda03a6..0000000 --- a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireApplication.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * DesfireApplication.java - * - * Copyright (C) 2011 Eric Butler - * - * Authors: - * Eric Butler - * - * 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 . - */ - -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 CREATOR = new Parcelable.Creator() { - 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; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.java b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.java deleted file mode 100644 index b737d38..0000000 --- a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.java +++ /dev/null @@ -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); - } -} diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.kt b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireException.kt new file mode 100644 index 0000000..7486991 --- /dev/null +++ b/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) {} +} diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.java b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.java deleted file mode 100644 index 80ae5fc..0000000 --- a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * DesfireFile.java - * - * Copyright (C) 2011 Eric Butler - * - * Authors: - * Eric Butler - * - * 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 . - */ - -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 CREATOR = new Parcelable.Creator() { - 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; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.kt b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFile.kt new file mode 100644 index 0000000..322b59e --- /dev/null +++ b/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 + * + * 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 . + */ + +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 + + init { + + val settings = fileSettings as RecordDesfireFileSettings + + val records = arrayOfNulls(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 = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel): DesfireFile { + val fileId = source.readInt() + + val isError = source.readInt() == 1 + + return if (!isError) { + val fileSettings = + source.readParcelable(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 { + return arrayOfNulls(size) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.java b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.java deleted file mode 100644 index 17220b7..0000000 --- a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * DesfireFileSettings.java - * - * Copyright (C) 2011 Eric Butler - * - * Authors: - * Eric Butler - * - * 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 . - */ - -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 CREATOR = new Parcelable.Creator() { - 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]); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.kt b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireFileSettings.kt new file mode 100644 index 0000000..f81599f --- /dev/null +++ b/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 + * + * 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 . + */ + +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 = object : Parcelable.Creator { + 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 { + return arrayOfNulls(size) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.java b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.java deleted file mode 100644 index becc763..0000000 --- a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * DesfireManufacturingData.java - * - * Copyright (C) 2011 Eric Butler - * - * Authors: - * Eric Butler - * - * 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 . - */ - -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; - public final int swMinorVersion; - public final int swStorageSize; - public final int swProtocol; - - public final int uid; - public final int batchNo; - public final int weekProd; - public final int yearProd; - - public DesfireManufacturingData (byte[] data) { - ByteArrayInputStream stream = new ByteArrayInputStream(data); - hwVendorID = stream.read(); - hwType = stream.read(); - hwSubType = stream.read(); - hwMajorVersion = stream.read(); - hwMinorVersion = stream.read(); - hwStorageSize = stream.read(); - hwProtocol = stream.read(); - - swVendorID = stream.read(); - swType = stream.read(); - swSubType = stream.read(); - swMajorVersion = stream.read(); - swMinorVersion = stream.read(); - swStorageSize = stream.read(); - swProtocol = stream.read(); - - // FIXME: This has fewer digits than what's contained in EXTRA_ID, why? - byte[] buf = new byte[7]; - stream.read(buf, 0, buf.length); - uid = Utils.byteArrayToInt(buf); - - // FIXME: This is returning a negative number. Probably is unsigned. - buf = new byte[5]; - stream.read(buf, 0, buf.length); - batchNo = Utils.byteArrayToInt(buf); - - // FIXME: These numbers aren't making sense. - weekProd = stream.read(); - yearProd = stream.read(); - } - - public static DesfireManufacturingData fromXml (Element element) { - return new DesfireManufacturingData(element); - } - - private DesfireManufacturingData (Element element) { - hwVendorID = Integer.parseInt(element.getElementsByTagName("hw-vendor-id").item(0).getTextContent()); - hwType = Integer.parseInt(element.getElementsByTagName("hw-type").item(0).getTextContent()); - hwSubType = Integer.parseInt(element.getElementsByTagName("hw-sub-type").item(0).getTextContent()); - hwMajorVersion = Integer.parseInt(element.getElementsByTagName("hw-major-version").item(0).getTextContent()); - hwMinorVersion = Integer.parseInt(element.getElementsByTagName("hw-minor-version").item(0).getTextContent()); - hwStorageSize = Integer.parseInt(element.getElementsByTagName("hw-storage-size").item(0).getTextContent()); - hwProtocol = Integer.parseInt(element.getElementsByTagName("hw-protocol").item(0).getTextContent()); - - swVendorID = Integer.parseInt(element.getElementsByTagName("sw-vendor-id").item(0).getTextContent()); - swType = Integer.parseInt(element.getElementsByTagName("sw-type").item(0).getTextContent()); - swSubType = Integer.parseInt(element.getElementsByTagName("sw-sub-type").item(0).getTextContent()); - swMajorVersion = Integer.parseInt(element.getElementsByTagName("sw-major-version").item(0).getTextContent()); - swMinorVersion = Integer.parseInt(element.getElementsByTagName("sw-minor-version").item(0).getTextContent()); - swStorageSize = Integer.parseInt(element.getElementsByTagName("sw-storage-size").item(0).getTextContent()); - swProtocol = Integer.parseInt(element.getElementsByTagName("sw-protocol").item(0).getTextContent()); - - uid = Integer.parseInt(element.getElementsByTagName("uid").item(0).getTextContent()); - batchNo = Integer.parseInt(element.getElementsByTagName("batch-no").item(0).getTextContent()); - weekProd = Integer.parseInt(element.getElementsByTagName("week-prod").item(0).getTextContent()); - yearProd = Integer.parseInt(element.getElementsByTagName("year-prod").item(0).getTextContent()); - } - - private DesfireManufacturingData (Parcel parcel) { - hwVendorID = parcel.readInt(); - hwType = parcel.readInt(); - hwSubType = parcel.readInt(); - hwMajorVersion = parcel.readInt(); - hwMinorVersion = parcel.readInt(); - hwStorageSize = parcel.readInt(); - hwProtocol = parcel.readInt(); - - swVendorID = parcel.readInt(); - swType = parcel.readInt(); - swSubType = parcel.readInt(); - swMajorVersion = parcel.readInt(); - swMinorVersion = parcel.readInt(); - swStorageSize = parcel.readInt(); - swProtocol = parcel.readInt(); - - uid = parcel.readInt(); - batchNo = parcel.readInt(); - weekProd = parcel.readInt(); - yearProd = parcel.readInt(); - } - - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(hwVendorID); - parcel.writeInt(hwType); - parcel.writeInt(hwSubType); - parcel.writeInt(hwMajorVersion); - parcel.writeInt(hwMinorVersion); - parcel.writeInt(hwStorageSize); - parcel.writeInt(hwProtocol); - - parcel.writeInt(swVendorID); - parcel.writeInt(swType); - parcel.writeInt(swSubType); - parcel.writeInt(swMajorVersion); - parcel.writeInt(swMinorVersion); - parcel.writeInt(swStorageSize); - parcel.writeInt(swProtocol); - - parcel.writeInt(uid); - parcel.writeInt(batchNo); - parcel.writeInt(weekProd); - parcel.writeInt(yearProd); - } - - public int describeContents() { - return 0; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public DesfireManufacturingData createFromParcel(Parcel source) { - return new DesfireManufacturingData(source); - } - - public DesfireManufacturingData[] newArray(int size) { - return new DesfireManufacturingData[size]; - } - }; -} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.kt b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.kt new file mode 100644 index 0000000..76ee098 --- /dev/null +++ b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireManufacturingData.kt @@ -0,0 +1,180 @@ +/* + * DesfireManufacturingData.java + * + * Copyright (C) 2011 Eric Butler + * + * Authors: + * Eric Butler + * + * 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 . + */ + +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 + +class DesfireManufacturingData : Parcelable { + private val hwVendorID: Int + private val hwType: Int + private val hwSubType: Int + private val hwMajorVersion: Int + private val hwMinorVersion: Int + private val hwStorageSize: Int + private val hwProtocol: Int + + private val swVendorID: Int + private val swType: Int + private val swSubType: Int + private val swMajorVersion: Int + private val swMinorVersion: Int + private val swStorageSize: Int + private val swProtocol: Int + + private val uid: Int + private val batchNo: Int + private val weekProd: Int + private val yearProd: Int + + constructor(data: ByteArray) { + val stream = ByteArrayInputStream(data) + hwVendorID = stream.read() + hwType = stream.read() + hwSubType = stream.read() + hwMajorVersion = stream.read() + hwMinorVersion = stream.read() + hwStorageSize = stream.read() + hwProtocol = stream.read() + + swVendorID = stream.read() + swType = stream.read() + swSubType = stream.read() + swMajorVersion = stream.read() + swMinorVersion = stream.read() + swStorageSize = stream.read() + swProtocol = stream.read() + + // FIXME: This has fewer digits than what's contained in EXTRA_ID, why? + var buf = ByteArray(7) + stream.read(buf, 0, buf.size) + uid = Utils.byteArrayToInt(buf) + + // FIXME: This is returning a negative number. Probably is unsigned. + buf = ByteArray(5) + stream.read(buf, 0, buf.size) + batchNo = Utils.byteArrayToInt(buf) + + // FIXME: These numbers aren't making sense. + weekProd = stream.read() + yearProd = stream.read() + } + + private constructor(element: Element) { + hwVendorID = Integer.parseInt(element.getElementsByTagName("hw-vendor-id").item(0).textContent) + hwType = Integer.parseInt(element.getElementsByTagName("hw-type").item(0).textContent) + hwSubType = Integer.parseInt(element.getElementsByTagName("hw-sub-type").item(0).textContent) + hwMajorVersion = Integer.parseInt(element.getElementsByTagName("hw-major-version").item(0).textContent) + hwMinorVersion = Integer.parseInt(element.getElementsByTagName("hw-minor-version").item(0).textContent) + hwStorageSize = Integer.parseInt(element.getElementsByTagName("hw-storage-size").item(0).textContent) + hwProtocol = Integer.parseInt(element.getElementsByTagName("hw-protocol").item(0).textContent) + + swVendorID = Integer.parseInt(element.getElementsByTagName("sw-vendor-id").item(0).textContent) + swType = Integer.parseInt(element.getElementsByTagName("sw-type").item(0).textContent) + swSubType = Integer.parseInt(element.getElementsByTagName("sw-sub-type").item(0).textContent) + swMajorVersion = Integer.parseInt(element.getElementsByTagName("sw-major-version").item(0).textContent) + swMinorVersion = Integer.parseInt(element.getElementsByTagName("sw-minor-version").item(0).textContent) + swStorageSize = Integer.parseInt(element.getElementsByTagName("sw-storage-size").item(0).textContent) + swProtocol = Integer.parseInt(element.getElementsByTagName("sw-protocol").item(0).textContent) + + uid = Integer.parseInt(element.getElementsByTagName("uid").item(0).textContent) + batchNo = Integer.parseInt(element.getElementsByTagName("batch-no").item(0).textContent) + weekProd = Integer.parseInt(element.getElementsByTagName("week-prod").item(0).textContent) + yearProd = Integer.parseInt(element.getElementsByTagName("year-prod").item(0).textContent) + } + + private constructor(parcel: Parcel) { + hwVendorID = parcel.readInt() + hwType = parcel.readInt() + hwSubType = parcel.readInt() + hwMajorVersion = parcel.readInt() + hwMinorVersion = parcel.readInt() + hwStorageSize = parcel.readInt() + hwProtocol = parcel.readInt() + + swVendorID = parcel.readInt() + swType = parcel.readInt() + swSubType = parcel.readInt() + swMajorVersion = parcel.readInt() + swMinorVersion = parcel.readInt() + swStorageSize = parcel.readInt() + swProtocol = parcel.readInt() + + uid = parcel.readInt() + batchNo = parcel.readInt() + weekProd = parcel.readInt() + yearProd = parcel.readInt() + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeInt(hwVendorID) + parcel.writeInt(hwType) + parcel.writeInt(hwSubType) + parcel.writeInt(hwMajorVersion) + parcel.writeInt(hwMinorVersion) + parcel.writeInt(hwStorageSize) + parcel.writeInt(hwProtocol) + + parcel.writeInt(swVendorID) + parcel.writeInt(swType) + parcel.writeInt(swSubType) + parcel.writeInt(swMajorVersion) + parcel.writeInt(swMinorVersion) + parcel.writeInt(swStorageSize) + parcel.writeInt(swProtocol) + + parcel.writeInt(uid) + parcel.writeInt(batchNo) + parcel.writeInt(weekProd) + parcel.writeInt(yearProd) + } + + override fun describeContents(): Int { + return 0 + } + + companion object { + + @Suppress("unused") + fun fromXml(element: Element): DesfireManufacturingData { + return DesfireManufacturingData(element) + } + + @Suppress("unused") + @JvmField + val CREATOR: Parcelable.Creator = + object : Parcelable.Creator { + override fun createFromParcel(source: Parcel): DesfireManufacturingData { + return DesfireManufacturingData(source) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.java b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.java deleted file mode 100644 index 28404d7..0000000 --- a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * DesfireProtocol.java - * - * Copyright (C) 2011 Eric Butler - * - * Authors: - * Eric Butler - * - * 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 . - */ - -package com.codebutler.farebot.card.desfire; - -import android.nfc.tech.IsoDep; -import com.codebutler.farebot.Utils; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; - -public class DesfireProtocol { - /* Commands */ - static final byte GET_MANUFACTURING_DATA = (byte) 0x60; - static final byte GET_APPLICATION_DIRECTORY = (byte) 0x6A; - static final byte GET_ADDITIONAL_FRAME = (byte) 0xAF; - static final byte SELECT_APPLICATION = (byte) 0x5A; - static final byte READ_DATA = (byte) 0xBD; - static final byte READ_RECORD = (byte) 0xBB; - static final byte READ_VALUE = (byte) 0x6C; - static final byte GET_FILES = (byte) 0x6F; - static final byte GET_FILE_SETTINGS = (byte) 0xF5; - - /* Status codes */ - static final byte OPERATION_OK = (byte) 0x00; - static final byte PERMISSION_DENIED = (byte) 0x9D; - static final byte ADDITIONAL_FRAME = (byte) 0xAF; - - private IsoDep mTagTech; - - public DesfireProtocol(IsoDep tagTech) { - mTagTech = tagTech; - } - - public DesfireManufacturingData getManufacturingData() throws DesfireException { - byte[] respBuffer = sendRequest(GET_MANUFACTURING_DATA); - - if (respBuffer.length != 28) - throw new DesfireException("Invalid response"); - - return new DesfireManufacturingData(respBuffer); - } - - public int[] getAppList() throws DesfireException { - byte[] appDirBuf = sendRequest(GET_APPLICATION_DIRECTORY); - - int[] appIds = new int[appDirBuf.length / 3]; - - for (int app = 0; app < appDirBuf.length; app += 3) { - byte[] appId = new byte[3]; - System.arraycopy(appDirBuf, app, appId, 0, 3); - - appIds[app / 3] = Utils.byteArrayToInt(appId); - } - - return appIds; - } - - public void selectApp (int appId) throws DesfireException { - byte[] appIdBuff = new byte[3]; - appIdBuff[0] = (byte) ((appId & 0xFF0000) >> 16); - appIdBuff[1] = (byte) ((appId & 0xFF00) >> 8); - appIdBuff[2] = (byte) (appId & 0xFF); - - sendRequest(SELECT_APPLICATION, appIdBuff); - } - - public int[] getFileList() throws DesfireException { - byte[] buf = sendRequest(GET_FILES); - int[] fileIds = new int[buf.length]; - for (int x = 0; x < buf.length; x++) { - fileIds[x] = (int)buf[x]; - } - return fileIds; - } - - public DesfireFileSettings getFileSettings (int fileNo) throws DesfireException { - byte[] data = new byte[0]; - data = sendRequest(GET_FILE_SETTINGS, new byte[] { (byte) fileNo }); - return DesfireFileSettings.Create(data); - } - - public byte[] readFile (int fileNo) throws DesfireException { - return sendRequest(READ_DATA, new byte[] { - (byte) fileNo, - (byte) 0x0, (byte) 0x0, (byte) 0x0, - (byte) 0x0, (byte) 0x0, (byte) 0x0 - }); - } - - public byte[] readRecord (int fileNum) throws DesfireException { - return sendRequest(READ_RECORD, new byte[]{ - (byte) fileNum, - (byte) 0x0, (byte) 0x0, (byte) 0x0, - (byte) 0x0, (byte) 0x0, (byte) 0x0 - }); - } - - public int readValue(int fileNum) throws DesfireException { - byte[] buf = sendRequest(READ_VALUE, new byte[]{ - (byte) fileNum - }); - ArrayUtils.reverse(buf); - return Utils.byteArrayToInt(buf); - } - - - private byte[] sendRequest (byte command) throws DesfireException { - return sendRequest(command, null); - } - - private byte[] sendRequest (byte command, byte[] parameters) throws DesfireException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - - byte[] recvBuffer = new byte[0]; - try { - recvBuffer = mTagTech.transceive(wrapMessage(command, parameters)); - } catch (IOException e) { - throw new DesfireException(e); - } - - while (true) { - if (recvBuffer[recvBuffer.length - 2] != (byte) 0x91) - throw new DesfireException("Invalid response"); - - output.write(recvBuffer, 0, recvBuffer.length - 2); - - byte status = recvBuffer[recvBuffer.length - 1]; - if (status == OPERATION_OK) { - break; - } else if (status == ADDITIONAL_FRAME) { - try { - recvBuffer = mTagTech.transceive(wrapMessage(GET_ADDITIONAL_FRAME, null)); - } catch (IOException e) { - throw new DesfireException(e); - } - } else if (status == PERMISSION_DENIED) { - throw new DesfireException("Permission denied"); - } else { - throw new DesfireException("Unknown status code: " + Integer.toHexString(status & 0xFF)); - } - } - - return output.toByteArray(); - } - - private byte[] wrapMessage (byte command, byte[] parameters) throws DesfireException { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - - stream.write((byte) 0x90); - stream.write(command); - stream.write((byte) 0x00); - stream.write((byte) 0x00); - if (parameters != null) { - stream.write((byte) parameters.length); - try { - stream.write(parameters); - } catch (IOException e) { - throw new DesfireException(e); - } - } - stream.write((byte) 0x00); - - return stream.toByteArray(); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.kt b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.kt new file mode 100644 index 0000000..e78a521 --- /dev/null +++ b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.kt @@ -0,0 +1,213 @@ +/* + * DesfireProtocol.java + * + * Copyright (C) 2011 Eric Butler + * + * Authors: + * Eric Butler + * + * 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 . + */ + +package com.codebutler.farebot.card.desfire + +import android.nfc.tech.IsoDep +import com.codebutler.farebot.Utils + +import java.io.ByteArrayOutputStream +import java.io.IOException + +import org.apache.commons.lang3.ArrayUtils +import kotlin.experimental.and + +class DesfireProtocol(private val mTagTech: IsoDep) { + + @Suppress("unused") + val manufacturingData: DesfireManufacturingData + @Throws(DesfireException::class) + get() { + val respBuffer = sendRequest(GET_MANUFACTURING_DATA) + + if (respBuffer.size != 28) + throw DesfireException("Invalid response") + + return DesfireManufacturingData(respBuffer) + } + + @Suppress("unused") + val appList: IntArray + @Throws(DesfireException::class) + get() { + val appDirBuf = sendRequest(GET_APPLICATION_DIRECTORY) + + val appIds = IntArray(appDirBuf.size / 3) + + var app = 0 + while (app < appDirBuf.size) { + val appId = ByteArray(3) + System.arraycopy(appDirBuf, app, appId, 0, 3) + + appIds[app / 3] = Utils.byteArrayToInt(appId) + app += 3 + } + + return appIds + } + + val fileList: IntArray + @Throws(DesfireException::class) + get() { + val buf = sendRequest(GET_FILES) + val fileIds = IntArray(buf.size) + for (x in buf.indices) { + fileIds[x] = buf[x].toInt() + } + return fileIds + } + + @Throws(DesfireException::class) + fun selectApp(appId: Int) { + val appIdBuff = ByteArray(3) + appIdBuff[0] = (appId and 0xFF0000 shr 16).toByte() + appIdBuff[1] = (appId and 0xFF00 shr 8).toByte() + appIdBuff[2] = (appId and 0xFF).toByte() + + sendRequest(SELECT_APPLICATION, appIdBuff) + } + + @Throws(DesfireException::class) + fun getFileSettings(fileNo: Int): DesfireFileSettings { + val data = sendRequest(GET_FILE_SETTINGS, byteArrayOf(fileNo.toByte())) + return DesfireFileSettings.create(data) + } + + @Suppress("unused") + @Throws(DesfireException::class) + fun readFile(fileNo: Int): ByteArray { + return sendRequest( + READ_DATA, + byteArrayOf( + fileNo.toByte(), + 0x0.toByte(), + 0x0.toByte(), + 0x0.toByte(), + 0x0.toByte(), + 0x0.toByte(), + 0x0.toByte() + ) + ) + } + + @Suppress("unused") + @Throws(DesfireException::class) + fun readRecord(fileNum: Int): ByteArray { + return sendRequest( + READ_RECORD, + byteArrayOf( + fileNum.toByte(), + 0x0.toByte(), + 0x0.toByte(), + 0x0.toByte(), + 0x0.toByte(), + 0x0.toByte(), + 0x0.toByte() + ) + ) + } + + @Throws(DesfireException::class) + fun readValue(fileNum: Int): Int { + val buf = sendRequest(READ_VALUE, byteArrayOf(fileNum.toByte())) + ArrayUtils.reverse(buf) + return Utils.byteArrayToInt(buf) + } + + @Throws(DesfireException::class) + private fun sendRequest(command: Byte, parameters: ByteArray? = null): ByteArray { + val output = ByteArrayOutputStream() + + var recvBuffer: ByteArray + try { + recvBuffer = mTagTech.transceive(wrapMessage(command, parameters)) + } catch (e: IOException) { + throw DesfireException(e) + } + + while (true) { + if (recvBuffer[recvBuffer.size - 2] != 0x91.toByte()) + throw DesfireException("Invalid response") + + output.write(recvBuffer, 0, recvBuffer.size - 2) + + val status = recvBuffer[recvBuffer.size - 1] + if (status == OPERATION_OK) { + break + } else if (status == ADDITIONAL_FRAME) { + try { + recvBuffer = mTagTech.transceive(wrapMessage(GET_ADDITIONAL_FRAME, null)) + } catch (e: IOException) { + throw DesfireException(e) + } + + } else if (status == PERMISSION_DENIED) { + throw DesfireException("Permission denied") + } else { + throw DesfireException("Unknown status code: " + Integer.toHexString((status and 0xFF.toByte()).toInt())) + } + } + + return output.toByteArray() + } + + @Throws(DesfireException::class) + private fun wrapMessage(command: Byte, parameters: ByteArray?): ByteArray { + val stream = ByteArrayOutputStream() + + stream.write(0x90.toByte().toInt()) + stream.write(command.toInt()) + stream.write(0x00.toByte().toInt()) + stream.write(0x00.toByte().toInt()) + if (parameters != null) { + stream.write(parameters.size.toByte().toInt()) + try { + stream.write(parameters) + } catch (e: IOException) { + throw DesfireException(e) + } + + } + stream.write(0x00.toByte().toInt()) + + return stream.toByteArray() + } + + companion object { + /* Commands */ + internal const val GET_MANUFACTURING_DATA = 0x60.toByte() + internal const val GET_APPLICATION_DIRECTORY = 0x6A.toByte() + internal const val GET_ADDITIONAL_FRAME = 0xAF.toByte() + internal const val SELECT_APPLICATION = 0x5A.toByte() + internal const val READ_DATA = 0xBD.toByte() + internal const val READ_RECORD = 0xBB.toByte() + internal const val READ_VALUE = 0x6C.toByte() + internal const val GET_FILES = 0x6F.toByte() + internal const val GET_FILE_SETTINGS = 0xF5.toByte() + + /* Status codes */ + internal const val OPERATION_OK = 0x00.toByte() + internal const val PERMISSION_DENIED = 0x9D.toByte() + internal const val ADDITIONAL_FRAME = 0xAF.toByte() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireRecord.java b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireRecord.kt similarity index 76% rename from app/src/main/java/com/codebutler/farebot/card/desfire/DesfireRecord.java rename to app/src/main/java/com/codebutler/farebot/card/desfire/DesfireRecord.kt index 2dfeda4..d3989a6 100644 --- a/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireRecord.java +++ b/app/src/main/java/com/codebutler/farebot/card/desfire/DesfireRecord.kt @@ -20,16 +20,6 @@ * along with this program. If not, see . */ -package com.codebutler.farebot.card.desfire; +package com.codebutler.farebot.card.desfire -public class DesfireRecord { - private byte[] mData; - - public DesfireRecord (byte[] data) { - mData = data; - } - - public byte[] getData () { - return mData; - } -} \ No newline at end of file +class DesfireRecord(val data: ByteArray) \ No newline at end of file