1
votes

I cannot find any samples on how to get CPointer in Kotlin Multiplatform, and the documentation that exists doesn't help much. In my iOS source set, I need to build the Kotlin equivalent of the following Swift code (only including relevant parts of the code):

  ...(hex: String) {

if hex.hasPrefix("#") {
    let start = hex.index(hex.startIndex, offsetBy: 1)
         let scanner = Scanner(string: hexColor)
         var hexNumber: UInt64 = 0



          if scanner.scanHexInt64(&hexNumber) {

            r = CGFloat((hexNumber & 0xff000000) >> 24) / 255
           ....

The specific part I am having problems with is

scanner.scanHexInt64(&hexNumber)

This is the Kotlin code and the question

//input to function - hex: String
    val scanner = NSScanner(hex)
    if (hex.startsWith("#")) {
        scanner.scanLocation = 1u
    }
    var hexNumber : UInt32 = 0u
    /*Type mismatch.
    Required:
    CPointer<UIntVar /* = UIntVarOf<UInt> */>?
    Found:
    UInt32 /* = UInt */
     */
    //HOW TO GET CPOINTER TO hexNumber?
    scanner.scanHexInt(hexNumber)

Per documentation: (link)

Pointers and arrays are mapped to CPointer<T>?.

But how?

2

2 Answers

3
votes

Found an answer to my question. Have to use

memScoped

.

memScoped {
        var pointed : UIntVar = alloc<UIntVar>()
        scanner.scanHexInt(pointed.ptr)
        val alpha: CGFloat = 1.0
        val pointedValue = pointed.value
        val r: CGFloat = (((pointedValue and 0xFF0000) shr 16)/255.0)
        ....
}

The only source on the internet on this (with regards to applying it to get the pointer) here - link

memScoped

inline fun <R> memScoped(block: MemScope.() -> R): R
Runs given block providing allocation of memory which will be automatically disposed at the end of this scope

Within it, use the extension function alloc() to obtain CVariable

fun <reified T : CVariable> NativePlacement.alloc(): T

Which then gives you access to the pointer via yet another extension function

val <T : CPointed> T.ptr: CPointer<T>

All very clear in retrospect, and clear that originally approached the problem in the wrong way, looking to get the pointer by something like CPointer<UInt> = ... Official documentation at https://kotlinlang.org/docs/reference/native/c_interop.html

0
votes
import kotlinx.cinterop.UIntVar
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr
import platform.CoreGraphics.CGFloat
import platform.Foundation.NSScanner
import platform.Foundation.scanHexInt
import platform.UIKit.UIColor
import kotlinx.cinterop.alloc
import kotlinx.cinterop.value

fun hexToUIColor(hexStr: String): UIColor {
    var cString: String = hexStr.toUpperCase()

    if (cString.startsWith("#")) {
        cString = cString.removePrefix("#")
    }

    if (cString.length != 8) {
        return UIColor.grayColor
    }

    var a: UInt
    var r: UInt
    var g: UInt
    var b: UInt

    memScoped {
        val scanner = NSScanner(cString)
        var pointed : UIntVar = alloc<UIntVar>()
        scanner.scanHexInt(pointed.ptr)
        val alpha: CGFloat = 1.0
        val pointedValue: UInt = pointed.value

        a = ((pointedValue and 4278190080u) shl 24) / 255u
        r = ((pointedValue and 16711680u) shl 16) / 255u
        g = ((pointedValue and 65280u) shl 8) / 255u
        b = ((pointedValue and 255u) shl 0) / 255u

        return UIColor(red = r.toDouble(), green = g.toDouble(), blue = b.toDouble(), alpha = a.toDouble())
    }
}