ray ray - 2 months ago 9
Swift Question

How to pass an UnsafePointer<UInt8> to a C API by reference?

I wrote some Swift 2.2 code to interact with

OpenSSL
C APIs and now I'm trying to convert it to Swift 3.

In Swift 2

let octets = pkcs7_d_data(pkcs7_d_sign(receiptPKCS7).memory.contents)
var ptr = UnsafePointer<UInt8>(octets.memory.data)

// now pass pointer by reference
ASN1_get_object(&ptr, &length, &type, &xclass, end - ptr)


In Swift 3, I've had to make a couple changes

// use guard so i dont have to constantly unwrap these values

guard let octets = pkcs7_d_data(pkcs7_d_sign(receiptPKCS7).pointee.contents),
var ptr = UnsafePointer<UInt8>(octets.pointee.data) else {
return nil
}

ASN1_get_object(&ptr, &length, &type, &xclass, end - ptr)
// ^^^ this is now a compiler error


Unfortunately, I can no longer pass
ptr
to
ASN1_get_object
by reference, due to this error:

Cannot pass immutable value as inout argument: Implicit conversion from UnsafePointer<UInt8> to UnsafePointer<UInt8>? requires a temporary


and then the rest of the error is cut off (there's no expand arrow).

What I've tried:


  • changing the
    ptr
    assignment to
    UnsafePointer<UInt8>(octets.pointee.data)?
    but then I'm told that my existing assignment already produces an optional

  • changed the
    UnsafePointer
    to
    UnsafeMutablePointer



What needs to change here?

Answer

The problem seems to be that octets.pointee.data is a UnsafeMutablePointer<UInt8>!, but ASN1_get_object expects the address of a UnsafePointer<UInt8>?.

The following code compiles, but I could not test it:

if
    let octets = pkcs7_d_data(pkcs7_d_sign(receiptPKCS7).pointee.contents),
    let data = octets.pointee.data {

    var ptr: UnsafePointer? = UnsafePointer(data) // (*)
    var length = 0
    var tag: Int32 = 0
    var xclass: Int32 = 0

    ASN1_get_object(&ptr, &length, &tag, &xclass, Int(octets.pointee.length))
}

(*) is the pointer conversion which makes it compile.