247 lines
8.2 KiB
Kotlin
247 lines
8.2 KiB
Kotlin
/*
|
|
* 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)
|
|
}
|
|
}
|
|
}
|
|
} |