Эх сурвалжийг харах

added uppercase characters to the unicodeHexMap
changed Array<UInt8>(hex) for optimization
took functionality out of String.hexToBytes() and into String.streamHexBytes to share code with Array initializer

jose 8 жил өмнө
parent
commit
fd10774250

+ 5 - 6
Sources/CryptoSwift/Array+Extension.swift

@@ -34,14 +34,13 @@ extension Array where Element: Integer, Element.IntegerLiteralType == UInt8 {
 
     public init(hex: String) {
         self.init()
-
-        let utf8 = Array<Element.IntegerLiteralType>(hex.utf8)
-        let skip0x = hex.hasPrefix("0x") ? 2 : 0
-        for idx in stride(from: utf8.startIndex.advanced(by: skip0x), to: utf8.endIndex, by: utf8.startIndex.advanced(by: 2)) {
-            let byteHex = "\(UnicodeScalar(utf8[idx]))\(UnicodeScalar(utf8[idx.advanced(by: 1)]))"
-            if let byte = UInt8(byteHex, radix: 16) {
+        
+        do{
+            try hex.streamHexBytes { (byte) in
                 self.append(byte as! Element)
             }
+        } catch _ as NSError{
+            self.removeAll()
         }
     }
 }

+ 29 - 12
Sources/CryptoSwift/String+Extension.swift

@@ -60,33 +60,50 @@ extension String {
     }
     
     
-    private static var unicodeHexMap:[UnicodeScalar:UInt8] = ["0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"a":10,"b":11,"c":12,"d":13,"e":14,"f":15]
+    private static var unicodeHexMap:[UnicodeScalar:UInt8] = ["0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"a":10,"b":11,"c":12,"d":13,"e":14,"f":15,"A":10,"B":11,"C":12,"D":13,"E":14,"F":15]
     /**
      Converts the a hexadecimal string to a corresponding array of bytes.
      
      So the string "ff00" would get converted to [255, 0].
+     Supports odd number of characters by interpreting the last character as its' hex value ("f" produces [16] as if it was "0f").
      
      - Returns: An array of 8 bit unsigned integers (bytes).
      */
-    public func hexToBytes() -> [UInt8]{
-        var bytes:[UInt8] = []
+    public func hexToBytes() -> Array<UInt8>{
+        var bytes:Array<UInt8> = []
+        do{
+            try self.streamHexBytes { (byte) in
+                bytes.append(byte)
+            }
+        }catch _ as NSError{
+            return []
+        }
+        
+        return bytes
+    }
+    
+    // Allows str.hexToBytes() and Array<UInt8>(hex: str) to share the same code
+    // Old functionality returns a blank array upon encountering a non hex character so this method must throw in order to replicate that in methods relying on this method. (ex. "ffn" should return [] instead of [255])
+    // Consider switching NSError to custom Error enum
+    public func streamHexBytes(_ block:(UInt8)->Void) throws{
         var buffer:UInt8?
-        var skip = self.hasPrefix("0x") ? 2 : 0
+        var skip = hasPrefix("0x") ? 2 : 0
         for char in unicodeScalars.lazy {
-            guard skip == 0 else {skip -= 1;continue}
-            guard let value = String.unicodeHexMap[char] else {return []}
+            guard skip == 0 else {
+                skip -= 1
+                continue
+            }
+            guard let value = String.unicodeHexMap[char] else {
+                throw NSError(domain: "com.krzyzanowskim.CryptoSwift.hexParseError", code: 0, userInfo: nil)
+            }
             if let b = buffer {
-                let byte = b << 4 | value
-                bytes.append(byte)
+                block(b << 4 | value)
                 buffer = nil
             } else {
                 buffer = value
             }
         }
-        if let b = buffer{
-            bytes.append(b)
-        }
-        return bytes
+        if let b = buffer{block(b)}
     }
     
 }