/** * Utils.kt * * Copyright (C) 2011 Eric Butler * Copyright (C) 2019 * * 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 } } } }