Jojodmo
Jojodmo

Reputation: 23616

Convert Hexadecimal String to Base64 in Swift

Is there a way to convert a hexadecimal string to base64 in Swift? For example, I would like to convert:

BA5E64C0DE

to:

ul5kwN4=

It's possible to convert a normal string to base64 by using:

let hex: String = "BA5E64C0DE"

let utf8str: NSData = hex.dataUsingEncoding(NSUTF8StringEncoding)!
let base64Encoded: NSString = utf8str.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))

let base64: String = (base64Encoded as String)

But this would give a result of:

QkE1RTY0QzBERQ==

Because it's just treating the hex as a normal UTF-8 String, and not hexadecimal.

It's possible to convert it to base64 correctly by looping through every six hex characters and converting it to it's four respective base64 characters, but this would be highly inefficient, and is just plain stupid (there would need to be 17,830,160 if statements):

if(hex == "000000"){base64+="AAAA"}
else if(hex == "000001"){base64+="AAAB"}
else if(hex == "000002"){base64+="AAAC"}
else if(hex == "BA5E64"){base64+="ul5k"}
//...

It would be nice if there was something like this:

let hex: String = "BA5E64C0DE"

let data: NSData = hex.dataUsingEncoding(NSHexadecimalEncoding)!
let base64Encoded: NSString = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))

let base64: String = (base64Encoded as String)

But sadly, there's no NSHexadecimalEncoding. Is there any efficient way to convert a hexadecimal string to it's base64 representation in Swift?

Upvotes: 2

Views: 6435

Answers (2)

jqgsninimo
jqgsninimo

Reputation: 7068

  1. First, convert Hex String to Data using the following routine. (Worked in Swift 3.0.2)

    extension String {
        /// Expanded encoding
        ///
        /// - bytesHexLiteral: Hex string of bytes
        /// - base64: Base64 string
        enum ExpandedEncoding {
            /// Hex string of bytes
            case bytesHexLiteral
            /// Base64 string
            case base64
        }
    
        /// Convert to `Data` with expanded encoding
        ///
        /// - Parameter encoding: Expanded encoding
        /// - Returns: data
        func data(using encoding: ExpandedEncoding) -> Data? {
            switch encoding {
            case .bytesHexLiteral:
                guard self.characters.count % 2 == 0 else { return nil }
                var data = Data()
                var byteLiteral = ""
                for (index, character) in self.characters.enumerated() {
                    if index % 2 == 0 {
                        byteLiteral = String(character)
                    } else {
                        byteLiteral.append(character)
                        guard let byte = UInt8(byteLiteral, radix: 16) else { return nil }
                        data.append(byte)
                    }
                }
                return data
            case .base64:
                return Data(base64Encoded: self)
            }
        }
    }
    
  2. Then, convert Data to Base64 String using Data.base64EncodedString(options:).


Usage

let base64 = "BA5E64C0DE".data(using: .bytesHexLiteral)?.base64EncodedString()
if let base64 = base64 {
    print(base64)
    // Prints "ul5kwN4="
}

Upvotes: 2

Rob
Rob

Reputation: 438277

The base-64 string, "ul5kwN4=", translates to a binary NSData consisting of of five bytes BA, 5E, 64, C0, and DE.

Now, if you really had a string with the hexadecimal representation, you could convert it to a binary NSData using a routine like the one here: https://stackoverflow.com/a/26502285/1271826

Once you have a NSData, you could build your base 64 string:

let hexString = "BA5E64C0DE"
let binaryData = hexString.dataFromHexadecimalString()
let base64String = binaryData?.base64EncodedStringWithOptions(nil)

That generates the desired output, ul5kwN4=.

Upvotes: 6

Related Questions