Support UTF-32 conversion. (#2689)
This commit is contained in:
@@ -392,6 +392,12 @@ private class CString(val bytes: ByteArray): CValues<ByteVar>() {
|
||||
public val String.cstr: CValues<ByteVar>
|
||||
get() = CString(encodeToUtf8(this))
|
||||
|
||||
/**
|
||||
* @return the value of zero-terminated UTF-8-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.utf8: CValues<ByteVar>
|
||||
get() = CString(encodeToUtf8(this))
|
||||
|
||||
/**
|
||||
* Convert this list of Kotlin strings to C array of C strings,
|
||||
* allocating memory for the array and C strings with given [AutofreeScope].
|
||||
@@ -407,7 +413,7 @@ public fun Array<String>.toCStringArray(autofreeScope: AutofreeScope): CPointer<
|
||||
autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) })
|
||||
|
||||
|
||||
private class WCString(val chars: CharArray): CValues<UShortVar>() {
|
||||
private class U16CString(val chars: CharArray): CValues<UShortVar>() {
|
||||
override val size get() = 2 * (chars.size + 1)
|
||||
|
||||
override val align get() = 2
|
||||
@@ -425,16 +431,61 @@ private class WCString(val chars: CharArray): CValues<UShortVar>() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of zero-terminated UTF-16-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.wcstr: CValues<UShortVar>
|
||||
get() = WCString(this.toCharArray())
|
||||
get() = U16CString(this.toCharArray())
|
||||
|
||||
/**
|
||||
* TODO: should the name of the function reflect the encoding?
|
||||
*
|
||||
* @return the value of zero-terminated UTF-16-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.utf16: CValues<UShortVar>
|
||||
get() = U16CString(this.toCharArray())
|
||||
|
||||
private class U32CString(val chars: CharArray): CValues<IntVar>() {
|
||||
override val size get() = 4 * (chars.size + 1)
|
||||
|
||||
override val align get() = 4
|
||||
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<IntVar> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
|
||||
override fun place(placement: CPointer<IntVar>): CPointer<IntVar> {
|
||||
var indexIn = 0
|
||||
var indexOut = 0
|
||||
while (indexIn < chars.size) {
|
||||
var value = chars[indexIn++].toInt()
|
||||
if (value >= 0xd800 && value < 0xdc00) {
|
||||
// Surrogate pair.
|
||||
if (indexIn >= chars.size - 1) throw IllegalArgumentException()
|
||||
indexIn++
|
||||
val next = chars[indexIn].toInt()
|
||||
if (next < 0xdc00 || next >= 0xe000) throw IllegalArgumentException()
|
||||
value = 0x10000 + ((value and 0x3ff) shl 10) + (next and 0x3ff)
|
||||
}
|
||||
nativeMemUtils.putInt((placement + indexOut)!!.pointed, value)
|
||||
indexOut++
|
||||
}
|
||||
nativeMemUtils.putInt((placement + indexOut)!!.pointed, 0)
|
||||
return placement
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of zero-terminated UTF-32-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.utf32: CValues<IntVar>
|
||||
get() = U32CString(this.toCharArray())
|
||||
|
||||
|
||||
// TODO: optimize
|
||||
/**
|
||||
* @return the [kotlin.String] decoded from given zero-terminated UTF-8-encoded C string.
|
||||
*/
|
||||
// TODO: optimize
|
||||
public fun CPointer<ByteVar>.toKString(): String {
|
||||
public fun CPointer<ByteVar>.toKStringFromUtf8(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var length = 0
|
||||
@@ -447,6 +498,62 @@ public fun CPointer<ByteVar>.toKString(): String {
|
||||
return decodeFromUtf8(bytes)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the [kotlin.String] decoded from given zero-terminated UTF-8-encoded C string.
|
||||
*/
|
||||
public fun CPointer<ByteVar>.toKString(): String = this.toKStringFromUtf8()
|
||||
|
||||
/**
|
||||
* @return the [kotlin.String] decoded from given zero-terminated UTF-16-encoded C string.
|
||||
*/
|
||||
public fun CPointer<ShortVar>.toKStringFromUtf16(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var length = 0
|
||||
while (nativeBytes[length] != 0.toShort()) {
|
||||
++length
|
||||
}
|
||||
val chars = CharArray(length)
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
chars[index] = nativeBytes[index].toChar()
|
||||
++index
|
||||
}
|
||||
return String(chars)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the [kotlin.String] decoded from given zero-terminated UTF-32-encoded C string.
|
||||
*/
|
||||
public fun CPointer<IntVar>.toKStringFromUtf32(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var fromIndex = 0
|
||||
var toIndex = 0
|
||||
while (true) {
|
||||
val value = nativeBytes[fromIndex++]
|
||||
toIndex++
|
||||
if (value == 0) break
|
||||
if (value >= 0x10000 && value <= 0x10ffff) {
|
||||
toIndex++
|
||||
}
|
||||
}
|
||||
val length = toIndex
|
||||
val chars = CharArray(length)
|
||||
fromIndex = 0
|
||||
toIndex = 0
|
||||
while (toIndex < length) {
|
||||
var value = nativeBytes[fromIndex++]
|
||||
if (value >= 0x10000 && value <= 0x10ffff) {
|
||||
chars[toIndex++] = (((value - 0x10000) shr 10) or 0xd800).toChar()
|
||||
chars[toIndex++] = (((value - 0x10000) and 0x3ff) or 0xdc00).toChar()
|
||||
} else {
|
||||
chars[toIndex++] = value.toChar()
|
||||
}
|
||||
}
|
||||
return String(chars)
|
||||
}
|
||||
|
||||
public class MemScope : ArenaBase() {
|
||||
|
||||
val memScope: MemScope
|
||||
|
||||
@@ -127,38 +127,26 @@ internal object nativeMemUtils {
|
||||
}
|
||||
}
|
||||
|
||||
fun CPointer<ShortVar>.toKString(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var length = 0
|
||||
while (nativeBytes[length] != 0.toShort()) {
|
||||
++length
|
||||
}
|
||||
val bytes = CharArray(length)
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
bytes[index] = nativeBytes[index].toChar()
|
||||
++index
|
||||
}
|
||||
return String(bytes)
|
||||
}
|
||||
|
||||
fun CPointer<UShortVar>.toKString(): String {
|
||||
public fun CPointer<UShortVar>.toKStringFromUtf16(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var length = 0
|
||||
while (nativeBytes[length] != 0.toUShort()) {
|
||||
++length
|
||||
}
|
||||
val bytes = CharArray(length)
|
||||
val chars = kotlin.CharArray(length)
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
bytes[index] = nativeBytes[index].toShort().toChar()
|
||||
chars[index] = nativeBytes[index].toShort().toChar()
|
||||
++index
|
||||
}
|
||||
return String(bytes)
|
||||
return String(chars)
|
||||
}
|
||||
|
||||
public fun CPointer<ShortVar>.toKString(): String = this.toKStringFromUtf16()
|
||||
|
||||
public fun CPointer<UShortVar>.toKString(): String = this.toKStringFromUtf16()
|
||||
|
||||
@SymbolName("Kotlin_interop_malloc")
|
||||
private external fun malloc(size: Long, align: Int): NativePtr
|
||||
|
||||
|
||||
Reference in New Issue
Block a user