I'm going insane trying to get this to work
Trying to duplicate the following java function
Here is the code from Java
public static byte[] decodeHex(final String data) throws DecoderException {
return decodeHex(data.toCharArray());
}
public static byte[] decodeHex(final char[] data) throws DecoderException {
final int len = data.length;
if ((len & 0x01) != 0) {
throw new DecoderException("Odd number of characters.");
}
final byte[] out = new byte[len >> 1];
// two characters form the hex value.
for (int i = 0, j = 0; j < len; i++) {
int f = toDigit(data[j], j) << 4;
j++;
f = f | toDigit(data[j], j);
j++;
out[i] = (byte) (f & 0xFF);
}
return out;
}
protected static int toDigit(final char ch, final int index) throws DecoderException {
final int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new DecoderException("Illegal hexadecimal character " + ch + " at index " + index);
}
return digit;
}
given the following string 01e703000000000000
the byte array should contain
[1, -25, 3, 0, 0, 0, 0, 0, 0]
I thought this may be standard hex decoding so I used the usual decoding function I've been using
extension String {
/// A data representation of the hexadecimal bytes in this string.
var hexDecodedData: Data {
// Get the UTF8 characters of this string
let chars = Array(utf8)
// Keep the bytes in an UInt8 array and later convert it to Data
var bytes = [UInt8]()
bytes.reserveCapacity(count / 2)
// It is a lot faster to use a lookup map instead of stratal
let map: [UInt8] = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // HIJKLMNO
]
// Grab two characters at a time, map them and turn it into a byte
for i in stride(from: 0, to: count, by: 2) {
let index1 = Int(chars[i] & 0x1F ^ 0x10)
let index2 = Int(chars[i + 1] & 0x1F ^ 0x10)
bytes.append(map[index1] << 4 | map[index2])
}
return Data(bytes)
}
}
This results in
[1, 231, 3, 0, 0, 0, 0, 0, 0]
So the I tried converting the java code to swift myself
extension String {
// public static byte[] decodeHex(final char[] data) throws DecoderException
func decodeHex() throws -> [Int] {
let stringArray = Array(self)
let len = count
var out: [Int?] = Array(repeating: nil, count: len >> 1)
if (len & 0x01) != 0 {
throw HExDecodingError.oddNumberOfCharacters
}
var i = 0
var j = 0
while j < len {
var f: Int = try Self.toDigit(char: String(stringArray[j]), index: j)
j += 1
f = f | (try Self.toDigit(char: String(stringArray[j]), index: j))
j += 1
out[i] = f & 0xFF
i += 1
}
return out.compactMap { $0 }
}
enum HExDecodingError: Error {
case oddNumberOfCharacters
case illegalCharacter(String)
case conversionToDogotFailed(String, Int)
}
static func toDigit(char: String, index: Int) throws -> Int {
let digit = Int(char, radix: 16)
if digit == -1 {
throw HExDecodingError.illegalCharacter(char)
}
guard let digit = digit else {
throw HExDecodingError.conversionToDogotFailed(char, index)
}
return digit
}
}
Which results in
[1, 15, 3, 0, 0, 0, 0, 0, 0]
What is going on? what am I doing wrong
EDIT:
Also how can there possibly be a negative number in there since a byte array is represented as a [UInt8]
(_ text: S, radix: Int = 10) where S : StringProtocol`. It will fail instead of return `-1` in other words it would return `nil`– Leo Dabus Apr 10 '22 at 22:33