Есть ли способ препроцессора Swift для обнаружения включения моста в заголовок?

Единственный ответ, который я нашел, был в этом , и меня это не устраивает.

Я добавляю стандартный преобразователь MD5 в качестве расширения String:

/* ###################################################################################################################################### */
/**
 From here: https://stackoverflow.com/q/24123518/879365
 I am not making this public, because it requires the common crypto in the bridging header.
 */
fileprivate extension String {
    /* ################################################################## */
    /**
     - returns: the String, as an MD5 hash.
     */
    var md5: String {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = CUnsignedInt(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_MD5(str!, strLen, result)

        let hash = NSMutableString()

        for i in 0..<digestLen {
            hash.appendFormat("%02x", result[i])
        }

        result.deallocate()
        return hash as String
    }
}

Это требует, чтобы я добавил следующее к моему заголовку моста:

#import <CommonCrypto/CommonCrypto.h>

Поскольку я хотел бы добавить это в набор инструментов многократного использования, я хотел бы посмотреть, есть ли способ определить во время компиляции, используется ли общая криптографическая библиотека.

Есть ли способ настроить это как условную компиляцию?

Это не имеет большого значения, если нет; просто означает, что мне нужно настроить это как отдельный исходный файл.


person Chris Marshall    schedule 11.04.2019    source источник


Ответы (2)


Возможно, стоит отметить, что вы можете вызывать CC_MD5 без связующего заголовка, если вы используете dlsym для доступа к нему.

import Foundation

typealias CC_MD5_Type = @convention(c) (UnsafeRawPointer, UInt32, UnsafeMutableRawPointer) -> UnsafeMutableRawPointer

let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
let CC_MD5 = unsafeBitCast(dlsym(RTLD_DEFAULT, "CC_MD5")!, to: CC_MD5_Type.self)

var md5 = Data(count: 16)
md5.withUnsafeMutableBytes {
    _ = CC_MD5("abc", 3, $0)
}

assert(md5 == Data(bytes: [0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72]))
person rob mayoff    schedule 11.04.2019
comment
Даже лучше! Я даю вам зеленый чек за это! Спасибо! Я изменяю свой исходный вопрос с помощью кода решения. Я действительно это помню, но забыл. Спасибо! - person Chris Marshall; 11.04.2019
comment
@Rift Пожалуйста, не редактируйте ответ на свой вопрос; Я откатил ваше последнее редактирование. Если вы хотите поделиться своим решением, опубликуйте ответ в поле для ответов. Вы по-прежнему можете оставить ответ Роба помеченным как принятый, если хотите отдать ему должное. - person Cody Gray; 12.04.2019
comment
Сделаю. Я не хотел брать у него. - person Chris Marshall; 12.04.2019

Вот решение, которое я ударил. Это была смесь моего оригинального варианта и отличного ответа Роба. Это прекрасно работает (я использую его для создания ответов на Дайджест-аутентификацию RFC2617). Из-за использования встроенных ловушек мне больше не нужен соединительный заголовок, и я могу добавить его в свой набор расширений String.

довольно классический случай, когда правильный ответ исходит совсем из другого места, чем я искал. Я люблю когда это случается.

Вот:

public extension String {
    /* ################################################################## */
    /**
     From here: https://stackoverflow.com/q/24123518/879365, but modified from here: https://stackoverflow.com/a/55639723/879365
     - returns: an MD5 hash of the String
     */
    var md5: String {
        var hash = ""

        // Start by getting a C-style string of our string as UTF-8.
        if let str = self.cString(using: .utf8) {
            // This is a cast for the MD5 function. The convention attribute 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.
            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

            // This is where our MD5 hash goes. It's a simple 16-byte buffer.
            let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: CC_MD5_DIGEST_LENGTH)

            // Execute the MD5 hash. Save the result in our buffer.
            _ = CC_MD5(str, CUnsignedInt(str.count), result)

            // Turn it into a normal Swift String of hex digits.
            for i in 0..<CC_MD5_DIGEST_LENGTH {
                hash.append(String(format: "%02x", result[i]))
            }

            // Don't need this anymore.
            result.deallocate()
        }

        return hash
    }
}
person Chris Marshall    schedule 12.04.2019