3

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?

jww
  • 97,681
  • 90
  • 411
  • 885
ray
  • 1,966
  • 4
  • 24
  • 39
  • I haven't used Swift 3 yet, but I was dealing with similar in 2.3 the other day. Does directly doing `ASN1_get_object(&octet.pointee.data...)` not do what you need? – jscs Oct 06 '16 at 18:21
  • First, it still throws an error about not passing an immutable as inout, and second I'd like to keep a separate reference as I move the `ptr` around. – ray Oct 06 '16 at 20:08

1 Answers1

3

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.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • This appears to work, but am I not losing anything by not specifying `UInt8`? Also I can't assign `ptr` like this when it's in a `guard` condition so it seems I now have to unwrap it each time I use it. – ray Oct 06 '16 at 20:30
  • @ray: `ptr` has the type `UnsafePointer?`, you can verify that with option-click on the variable in Xcode. The `UInt8` is inferred automatically, you could more verbosely write `var ptr: UnsafePointer? = UnsafePointer(data)`. – Can't you define `ptr` *after* the guard statement? – Martin R Oct 06 '16 at 20:36
  • I can, I'm just sad about the fact that I can't seem to assign pointer **and** specify that it's optional if it's part of a conditional. Once I define it outside `guard`, I have to unwrap `ptr` every time I use it. – ray Oct 06 '16 at 21:04