93 lines
3.1 KiB
Scala
93 lines
3.1 KiB
Scala
package gs.hex.v0
|
|
|
|
object Hex:
|
|
|
|
private val HexChars: Array[Char] = Array(
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
|
|
'f'
|
|
)
|
|
|
|
// Leverage cache to avoid operations.
|
|
private val Digits: Array[Int] = Array(
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
|
|
-1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1
|
|
)
|
|
|
|
/** Convert the given raw data to a hexadecimal string.
|
|
*
|
|
* @param data
|
|
* The data to convert.
|
|
* @return
|
|
* The output hexadecimal string.
|
|
*/
|
|
def toHexString(data: Array[Byte]): String =
|
|
var index = 0
|
|
val ch: Array[Char] = new Array(data.length * 2)
|
|
data.foreach { byte =>
|
|
ch(index) = HexChars((byte & 0xf0) >> 4)
|
|
ch(index + 1) = HexChars(byte & 0x0f)
|
|
index = index + 2
|
|
}
|
|
new String(ch)
|
|
|
|
/** Convert the given hexadecimal string to a byte array.
|
|
*
|
|
* @param encoded
|
|
* The hexadecimal string.
|
|
* @return
|
|
* The encoded byte array, or nothing if the input is not a valid hex
|
|
* string.
|
|
*/
|
|
def fromHexString(encoded: String): Option[Array[Byte]] =
|
|
if encoded.isBlank() then Some(Array.empty)
|
|
else if encoded.length() % 2 != 0 then None
|
|
else
|
|
val size = encoded.length() / 2
|
|
val data: Array[Byte] = new Array(size)
|
|
|
|
// The "base" tracks the base index for character extraction.
|
|
var base = 0
|
|
|
|
// The "index" tracks the byte index being updated.
|
|
var index = 0
|
|
|
|
// Track if calculation failed for any reason.
|
|
var failed = false
|
|
|
|
// Populate each byte in the destination array.
|
|
while !failed && index < size do
|
|
// Extract the relevant characters.
|
|
val digit1 = Digits(encoded.charAt(base).toInt)
|
|
val digit2 = Digits(encoded.charAt(base + 1).toInt)
|
|
|
|
if digit1 >= 0 && digit2 >= 0 then
|
|
// Convert to byte and assign the result.
|
|
data(index) = pairToByte(digit1, digit2)
|
|
|
|
index = index + 1
|
|
base = base + 2
|
|
else
|
|
index = size
|
|
failed = true
|
|
|
|
if !failed then Some(data) else None
|
|
|
|
private inline def pairToByte(
|
|
digit1: Int,
|
|
digit2: Int
|
|
): Byte =
|
|
((digit1 << 4) + digit2).toByte
|
|
|
|
end Hex
|