You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
7.2 KiB
227 lines
7.2 KiB
/** |
|
* Utils.kt |
|
* |
|
* Copyright (C) 2011 Eric Butler |
|
* Copyright (C) 2019 <seil0@mosad.xyz> |
|
* |
|
* 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 |
|
} |
|
|
|
} |
|
} |
|
|
|
}
|
|
|