okarm
06/26/2022, 4:02 PMinternal actual fun encode(text: String, charset: Charset): ByteArray {
var cfCharsetName: CPointer<__CFString>? = null
try {
// (1) Cast a NSString as CFStringRef for the CF lookup function.
// The BridgingRetain function will transfer the ownership to us,
// making us responsible for freeing the memory.
cfCharsetName = CFBridgingRetain(charset.ianaName as NSString) as CFStringRef?
// (2) Using the prepared CFStringRef, find the CFStringEncoding.
val cfEncoding = CFStringConvertIANACharSetNameToEncoding(cfCharsetName)
if (cfEncoding == kCFStringEncodingInvalidId) {
throw RuntimeException("invalid encoding: ${charset.ianaName}")
}
// (3) Using the CF encoding, find the corresponding NSStringEncoding
val nsEncoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding)
// (4) Encode the Kotlin String using the NS Encoding. The resulting NSData
// lives in the ARC-enabled iOS runtime and since it does not escape the current
// scope, will be collected when scope ends.
val encodedData: NSData =
(text as NSString).dataUsingEncoding(nsEncoding, allowLossyConversion = true)
?: throw RuntimeException("encoder failed")
val encodedBytes = encodedData.bytes ?: throw RuntimeException("encoder failed")
// (5) Create a Kotlin-land ByteArray and copy over the encoded bytes
// from the ObjC-land NSData.
//
// <https://github.com/JetBrains/kotlin-native/issues/3172>
return ByteArray(encodedData.length.toInt()).apply {
usePinned { pinnedByteArray ->
memcpy(pinnedByteArray.addressOf(0), encodedBytes, encodedData.length)
}
}
} finally {
// Don't forget to free the unmanaged CF pointer!
CFRelease(cfCharsetName)
}
}