Last active
March 1, 2018 11:09
-
-
Save acalism/0a1c16cab2be8630507df8fb0a8c6b0f to your computer and use it in GitHub Desktop.
md5 计算。被注释掉的部分是较冗长的写法
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 需要在 xxx-Bridging-Header.h 中引入 CommonCrypto | |
// #import <CommonCrypto/CommonCrypto.h> // add to your xxx-Bridging-Header.h | |
// 所以在 playground 中无法测试下面的代码 ( NOT work with Playground ) | |
// 阅读代码时注意以下几点: | |
// 1. Data 本质是 UInt8 数组,所以 String.utf8.count 与 Data.count 是相等的(String 转换成 Data 前后) | |
// 2. 如果一个C方法接受的参数类型是 void*,即 Swift 里的 UnsafeRawPointer,那么它也接受 UnsafePointer<T> 类型 | |
// 3. 如果某个方法接受 UnsafePointer<UInt8> 类型参数,那么直接填入 String 也是可以的 | |
class Digest { | |
static func md5(_ data: Data) -> Data { | |
// var digestData = Data(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) | |
// digestData.withUnsafeMutableBytes { (digestBytes: UnsafeMutablePointer<UInt8>) -> Void in | |
// data.withUnsafeBytes { (messageBytes: UnsafePointer<Int8>) -> Void in | |
// CC_MD5(messageBytes, CC_LONG(data.count), digestBytes) | |
// } | |
// } | |
// return digestData | |
var digest = Array<UInt8>.init(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) | |
CC_MD5((data as NSData).bytes, CC_LONG(data.count), &digest) | |
return Data.init(bytes: digest) | |
} | |
static func md5(_ string: String) -> Data { | |
// var data = Data(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) | |
// data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in | |
// CC_MD5(string, CC_LONG(string.utf8.count), bytes) | |
// } | |
// return data | |
var digest = Array<UInt8>.init(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) | |
CC_MD5(string, CC_LONG(string.utf8.count), &digest) | |
return Data.init(bytes: digest) | |
} | |
static func md5(contentOf url: URL) throws -> Data { | |
let handle = try FileHandle(forReadingFrom: url) | |
var ctx = CC_MD5_CTX() | |
CC_MD5_Init(&ctx) | |
var count = 0 | |
repeat { | |
let fileData = handle.readData(ofLength: 256) // CHUNK_SIZE, or 1024 * 1024 | |
count = fileData.count | |
fileData.withUnsafeBytes({ (bytes: UnsafePointer<CChar>) -> Void in | |
CC_MD5_Update(&ctx, bytes, CC_LONG(count)) | |
}) | |
} while count > 0 | |
var digest = Array<UInt8>.init(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) | |
CC_MD5_Final(&digest, &ctx) | |
return Data.init(bytes: digest) | |
} | |
} | |
extension Data { | |
var md5: Data { | |
return Digest.md5(self) | |
} | |
// 事实上 hexDescription 和 hexEncodedString 结果是一致的 | |
// 前者取巧复用了 NSData 在 po 输出时就是16进制的特点 | |
// 后者对data的每个uint8转为16进制字符串并拼接在一起,更符合直观定义 | |
var hexDescription: String { | |
// 删除首尾的<>符号;删除空格 | |
return (self as NSData).description.trimmingCharacters(in: CharacterSet(charactersIn: "<>")).replacingOccurrences(of: " ", with: "") | |
} | |
var hexEncodedString: String { | |
return map { String(format: "%02hhx", $0) }.joined() | |
} | |
} | |
extension String { | |
var md5: Data { | |
return Digest.md5(self) | |
} | |
} | |
extension URL { | |
var md5: Data? { | |
return try? Digest.md5(contentOf: self) | |
} | |
} | |
// just a test function | |
func testMD5() { | |
let s = "A quick brown fox jumps over the lazy dog." | |
var ctx = CC_MD5_CTX() | |
var digest = Array<UInt8>.init(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) | |
CC_MD5_Init(&ctx) | |
CC_MD5_Update(&ctx, s, CC_LONG(s.utf8.count)) | |
CC_MD5_Final(&digest, &ctx) | |
print(digest.map { String(format:"%02x", $0) }.reduce("", +)) | |
print(Data.init(bytes: digest) as NSData) | |
print(s.md5.hexDescription) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment