> a new library for Apple platforms that provides idiomatic interfaces to system calls and low-level currency types
In other words, it's a set of native, type-safe Swift APIs that wrap the usual C system calls.
> System pervasively uses raw representable structs and option sets. These strong types help catch mistakes at compile time and are trivial to convert to and from the weaker C types.
> Errors are thrown using the standard language mechanism and cannot be missed. Further, all system calls interruptible by a signal take a defaulted-true retryOnInterrupt argument, causing them to retry on failure. When combined, these two changes dramatically simplify error and signal handling.
> FilePath is a managed, null-terminated bag-of-bytes that conforms to ExpressibleByStringLiteral — far safer to work with than a UnsafePointer<CChar> [Swift's spelling of `char *`].
I hope they meant in case of failure with EINTR.
var md5: String {
// The reason we are declaring these here, is so we don't have to actally import the CC module. We will just grope around and find the entry point, ourselves.
/// This is a cast for [the MD5 function](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_MD5.3cc.html#//apple_ref/doc/man/3cc/CC_MD5). [The convention attribute](https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID600) just says that it's a "raw" C function.
typealias CC_MD5_TYPE = @convention(c) (UnsafeRawPointer, UInt32, UnsafeMutableRawPointer) -> UnsafeMutableRawPointer
// This is a flag, telling the name lookup to happen in the global scope. No dlopen required.
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
// This loads a function pointer with the CommonCrypto MD5 function.
// [dlsym](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html) is a symbol lookup. It finds the symbol in our library, and returns a pointer to it.
let CC_MD5 = unsafeBitCast(dlsym(RTLD_DEFAULT, "CC_MD5")!, to: CC_MD5_TYPE.self)
// This is the length of the hash
let CC_MD5_DIGEST_LENGTH = 16
guard let strData = self.data(using: .utf8) else { return "" }
/// Creates an array of unsigned 8 bit integers that contains 16 zeros
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
/// CC_MD5 performs digest calculation and places the result in the caller-supplied buffer for digest (md)
/// Calls the given closure with a pointer to the underlying unsafe bytes of the strData’s contiguous storage.
_ = strData.withUnsafeBytes { (inBytes) -> Int in
// CommonCrypto
// extern unsigned char *CC_MD5(const void *data, CC_LONG len, unsigned char *md) --|
// OpenSSL |
// unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md) <-|
if let baseAddr = inBytes.baseAddress {
_ = CC_MD5(baseAddr, UInt32(strData.count), &digest)
}
return 0
}
// Convert the numerical response to an uppercase hex string.
return digest.reduce("") { (current, new) -> String in String(format: "\(current)%02X", new) }
}
As a Swift programmer, the above hurts my heart (but it works very well).[0] https://github.com/RiftValleySoftware/RVS_Generic_Swift_Tool...
extension String { var md5: String { let computed = Insecure.MD5.hash(data: self.data(using: .utf8)!) return computed.map { String(format: "%02hhx", $0) }.joined() } }
This is one of a couple of computed CC functions in a very general-purpose StringProtocol extension. I wanted to reduce as many external requirements as possible. I don’t even like importing Foundation, if I can help it.