String <-> CharArray, ByteArray conversions (#2973)
This commit is contained in:
@@ -3472,10 +3472,10 @@ task coverage_basic_library(type: RunStandaloneKonanTest) {
|
||||
|
||||
task buildKonanStdlibTests(type: BuildKonanTest) {
|
||||
outputSourceSetName = "testOutputStdlib"
|
||||
flags = [ "-Xmulti-platform", "-friend-modules", project.rootProject.file("${project.properties['konan.home']}/klib/common/stdlib") ]
|
||||
flags = [ "-Xmulti-platform", '-Xuse-experimental=kotlin.ExperimentalStdlibApi', "-friend-modules", project.rootProject.file("${project.properties['konan.home']}/klib/common/stdlib") ]
|
||||
def testSources = externalStdlibTestsDir.absolutePath
|
||||
compileList = [ "$testSources/stdlib/test", "$testSources/stdlib/common",
|
||||
"stdlib_external/utils.kt", "stdlib_external/jsCollectionFactoriesActuals.kt" ]
|
||||
"stdlib_external/utils.kt", "stdlib_external/text/StringEncodingTestNative.kt", "stdlib_external/jsCollectionFactoriesActuals.kt" ]
|
||||
excludeList = [ "$testSources/stdlib/test/internalAnnotations.kt" ]
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ fun <T: Any> checkThrows(e: KClass<T>, string: String, action: () -> Unit) {
|
||||
assertTrue(e.isInstance(exception),"""
|
||||
Wrong exception was thrown for string: $string
|
||||
Expected: ${e.qualifiedName}
|
||||
Actual: ${exception::class.qualifiedName}
|
||||
Actual: ${exception::class.qualifiedName}: $exception}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ fun test16to8CustomBorders() {
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8(-1, 4)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8(5, 10)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8(2, 10)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8(3, -2)}
|
||||
checkThrows(IllegalArgumentException::class, "Hello") { "Hello".toUtf8(3, -2)}
|
||||
|
||||
|
||||
// Test manual conversion with an exception if an input is invalid and custom borders.
|
||||
@@ -228,7 +228,7 @@ fun test16to8CustomBorders() {
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8OrThrow(-1, 4)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8OrThrow(5, 10)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8OrThrow(2, 10)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8OrThrow(3, -2)}
|
||||
checkThrows(IllegalArgumentException::class, "Hello") { "Hello".toUtf8OrThrow(3, -2)}
|
||||
}
|
||||
|
||||
fun testPrint() {
|
||||
@@ -294,8 +294,6 @@ fun test8to16CustomBorders() {
|
||||
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 3, 2)
|
||||
checkUtf8to16Replacing("",
|
||||
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 0, 0)
|
||||
checkUtf8to16Replacing("",
|
||||
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 10, 0)
|
||||
|
||||
checkUtf8to16Replacing("\uD800\uDC00\uD800\uDC00",
|
||||
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128),
|
||||
@@ -323,7 +321,8 @@ fun test8to16CustomBorders() {
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(-1, 4)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(5, 10)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(2, 10)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(3, -2)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(10, 0)}
|
||||
checkThrows(IllegalArgumentException::class, "Hello") { helloArray.stringFromUtf8(3, -2)}
|
||||
|
||||
// Conversion with throwing
|
||||
checkUtf8to16Throwing("He",
|
||||
@@ -334,8 +333,6 @@ fun test8to16CustomBorders() {
|
||||
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 3, 2)
|
||||
checkUtf8to16Throwing("",
|
||||
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 0, 0)
|
||||
checkUtf8to16Throwing("",
|
||||
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 10, 0)
|
||||
|
||||
checkUtf8to16Throwing("\uD800\uDC00\uD800\uDC00",
|
||||
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128),
|
||||
@@ -361,7 +358,8 @@ fun test8to16CustomBorders() {
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(-1, 4)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(5, 10)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(2, 10)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(3, -2)}
|
||||
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(10, 0)}
|
||||
checkThrows(IllegalArgumentException::class, "Hello") { helloArray.stringFromUtf8OrThrow(3, -2)}
|
||||
}
|
||||
// endregion
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package test.text
|
||||
|
||||
|
||||
internal actual val surrogateCodePointDecoding: String = "\uFFFD".repeat(3)
|
||||
|
||||
internal actual val surrogateCharEncoding: ByteArray = byteArrayOf(0xEF.toByte(), 0xBF.toByte(), 0xBD.toByte())
|
||||
@@ -17,3 +17,7 @@ public actual fun assertTypeEquals(expected: Any?, actual: Any?) {
|
||||
}
|
||||
|
||||
internal actual fun String.removeLeadingPlusOnJava6(): String = this
|
||||
|
||||
internal actual inline fun testOnNonJvm6And7(f: () -> Unit) {
|
||||
f()
|
||||
}
|
||||
|
||||
+3
-3
@@ -18,9 +18,9 @@
|
||||
buildKotlinVersion=1.3.40-dev-2251
|
||||
buildKotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_Compiler),number:1.3.40-dev-2251,pinned:true/artifacts/content/maven
|
||||
remoteRoot=konan_tests
|
||||
kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_Compiler),number:1.3.40-dev-2423,branch:default:true,pinned:true/artifacts/content/maven
|
||||
kotlinVersion=1.3.40-dev-2423
|
||||
testKotlinVersion=1.3.40-dev-2423
|
||||
kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_Compiler),number:1.3.50-dev-44,branch:default:true,pinned:true/artifacts/content/maven
|
||||
kotlinVersion=1.3.50-dev-44
|
||||
testKotlinVersion=1.3.50-dev-44
|
||||
# See https://teamcity.jetbrains.com/project.html?projectId=Kotlin_KotlinNativeShared&tab=projectOverview
|
||||
sharedRepo=https://dl.bintray.com/jetbrains/kotlin-native-dependencies
|
||||
sharedVersion=1.0-dev-57
|
||||
|
||||
@@ -52,8 +52,8 @@ void RUNTIME_NORETURN ThrowNumberFormatException();
|
||||
void RUNTIME_NORETURN ThrowOutOfMemoryError();
|
||||
// Throws not implemented error.
|
||||
void RUNTIME_NORETURN ThrowNotImplementedError();
|
||||
// Throws illegal character conversion exception (used in UTF8/UTF16 conversions).
|
||||
void RUNTIME_NORETURN ThrowIllegalCharacterConversionException();
|
||||
// Throws character coding exception (used in UTF8/UTF16 conversions).
|
||||
void RUNTIME_NORETURN ThrowCharacterCodingException();
|
||||
void RUNTIME_NORETURN ThrowIllegalArgumentException();
|
||||
void RUNTIME_NORETURN ThrowIllegalStateException();
|
||||
void RUNTIME_NORETURN ThrowInvalidMutabilityException(KConstRef where);
|
||||
|
||||
@@ -35,7 +35,7 @@ typedef KStdStringInserter utf16to8(const KChar*,const KChar*, KStdStringInserte
|
||||
KStdStringInserter utf16toUtf8OrThrow(const KChar* start, const KChar* end, KStdStringInserter result) {
|
||||
TRY_CATCH(result = utf8::utf16to8(start, end, result),
|
||||
result = utf8::unchecked::utf16to8(start, end, result),
|
||||
ThrowIllegalCharacterConversionException());
|
||||
ThrowCharacterCodingException());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ OBJ_GETTER(utf8ToUtf16OrThrow, const char* rawString, size_t rawStringLength) {
|
||||
uint32_t charCount;
|
||||
TRY_CATCH(charCount = utf8::utf16_length(rawString, end),
|
||||
charCount = utf8::unchecked::utf16_length(rawString, end),
|
||||
ThrowIllegalCharacterConversionException());
|
||||
ThrowCharacterCodingException());
|
||||
RETURN_RESULT_OF(utf8ToUtf16Impl<utf8::unchecked::utf8to16>, rawString, end, charCount);
|
||||
}
|
||||
|
||||
@@ -787,11 +787,7 @@ OBJ_GETTER(Kotlin_ByteArray_stringFromUtf8OrThrow, KConstRef thiz, KInt start, K
|
||||
RETURN_RESULT_OF0(TheEmptyString);
|
||||
}
|
||||
const char* rawString = byteArrayAsCString(thiz, start, size);
|
||||
KInt realSize = 0;
|
||||
while (rawString[realSize] != 0 && realSize < size) {
|
||||
realSize++;
|
||||
}
|
||||
RETURN_RESULT_OF(utf8ToUtf16OrThrow, rawString, realSize);
|
||||
RETURN_RESULT_OF(utf8ToUtf16OrThrow, rawString, size);
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_ByteArray_stringFromUtf8, KConstRef thiz, KInt start, KInt size) {
|
||||
@@ -799,11 +795,7 @@ OBJ_GETTER(Kotlin_ByteArray_stringFromUtf8, KConstRef thiz, KInt start, KInt siz
|
||||
RETURN_RESULT_OF0(TheEmptyString);
|
||||
}
|
||||
const char* rawString = byteArrayAsCString(thiz, start, size);
|
||||
KInt realSize = 0;
|
||||
while (rawString[realSize] != 0 && realSize < size) {
|
||||
realSize++;
|
||||
}
|
||||
RETURN_RESULT_OF(utf8ToUtf16, rawString, realSize);
|
||||
RETURN_RESULT_OF(utf8ToUtf16, rawString, size);
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_String_toUtf8, KString thiz, KInt start, KInt size) {
|
||||
@@ -833,12 +825,12 @@ OBJ_GETTER(Kotlin_String_fromCharArray, KConstRef thiz, KInt start, KInt size) {
|
||||
RETURN_OBJ(result->obj());
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_String_toCharArray, KString string) {
|
||||
OBJ_GETTER(Kotlin_String_toCharArray, KString string, KInt start, KInt size) {
|
||||
ArrayHeader* result = AllocArrayInstance(
|
||||
theCharArrayTypeInfo, string->count_, OBJ_RESULT)->array();
|
||||
theCharArrayTypeInfo, size, OBJ_RESULT)->array();
|
||||
memcpy(CharArrayAddressOfElementAt(result, 0),
|
||||
CharArrayAddressOfElementAt(string, 0),
|
||||
string->count_ * sizeof(KChar));
|
||||
CharArrayAddressOfElementAt(string, start),
|
||||
size * sizeof(KChar));
|
||||
RETURN_OBJ(result->obj());
|
||||
}
|
||||
|
||||
|
||||
@@ -89,10 +89,16 @@ namespace internal
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u32>
|
||||
inline bool is_out_of_unicode_domain(u32 cp)
|
||||
{
|
||||
return cp > CODE_POINT_MAX;
|
||||
}
|
||||
|
||||
template <typename u32>
|
||||
inline bool is_code_point_valid(u32 cp)
|
||||
{
|
||||
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
|
||||
return (!utf8::internal::is_out_of_unicode_domain(cp) && !utf8::internal::is_surrogate(cp));
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
@@ -146,7 +152,9 @@ namespace internal
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
|
||||
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
|
||||
|
||||
#define UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(CP, LENGTH) {if (utf8::internal::is_overlong_sequence(CP, LENGTH)) return OVERLONG_SEQUENCE;}
|
||||
|
||||
/// get_sequence_x functions decode utf-8 sequences of the length x
|
||||
template <typename octet_iterator>
|
||||
@@ -172,6 +180,8 @@ namespace internal
|
||||
|
||||
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
|
||||
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 2)
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
@@ -187,6 +197,11 @@ namespace internal
|
||||
|
||||
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
|
||||
if (utf8::internal::is_surrogate(code_point))
|
||||
return INVALID_CODE_POINT;
|
||||
|
||||
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 3)
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
@@ -206,6 +221,11 @@ namespace internal
|
||||
|
||||
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
|
||||
if (utf8::internal::is_out_of_unicode_domain(code_point))
|
||||
return INVALID_CODE_POINT;
|
||||
|
||||
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 4)
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
@@ -251,23 +271,14 @@ namespace internal
|
||||
}
|
||||
|
||||
if (err == UTF8_OK) {
|
||||
// Decoding succeeded. Now, security checks...
|
||||
if (utf8::internal::is_code_point_valid(cp)) {
|
||||
if (!utf8::internal::is_overlong_sequence(cp, length)){
|
||||
// Passed! Return here.
|
||||
code_point = cp;
|
||||
++it;
|
||||
return UTF8_OK;
|
||||
}
|
||||
else
|
||||
err = OVERLONG_SEQUENCE;
|
||||
}
|
||||
else
|
||||
err = INVALID_CODE_POINT;
|
||||
// Decoding succeeded.
|
||||
code_point = cp;
|
||||
++it;
|
||||
} else {
|
||||
// Failure branch - restore the original value of the iterator
|
||||
it = original_it;
|
||||
}
|
||||
|
||||
// Failure branch - restore the original value of the iterator
|
||||
it = original_it;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,13 +37,13 @@ uint32_t next(octet_iterator &it, const octet_iterator end, uint32_t replacement
|
||||
case internal::UTF8_OK :
|
||||
return cp;
|
||||
case internal::INVALID_LEAD :
|
||||
case internal::INVALID_CODE_POINT :
|
||||
case internal::OVERLONG_SEQUENCE :
|
||||
it++;
|
||||
return replacement;
|
||||
case internal::NOT_ENOUGH_ROOM :
|
||||
case internal::INCOMPLETE_SEQUENCE :
|
||||
case internal::OVERLONG_SEQUENCE :
|
||||
case internal::INVALID_CODE_POINT :
|
||||
// The whole invalid sequence is replaced with one replacement codepoint.
|
||||
// The whole incomplete sequence is replaced with one replacement codepoint.
|
||||
for (it++; it < end && utf8::internal::is_trail(*it); it++);
|
||||
return replacement;
|
||||
}
|
||||
|
||||
@@ -166,6 +166,7 @@ public actual open class NumberFormatException : IllegalArgumentException {
|
||||
actual constructor(message: String?) : super(message)
|
||||
}
|
||||
|
||||
// TODO: Deprecate and replace with CharacterCodingException
|
||||
public open class IllegalCharacterConversionException : IllegalArgumentException {
|
||||
|
||||
constructor(): super()
|
||||
|
||||
@@ -8,40 +8,67 @@ package kotlin.native
|
||||
/**
|
||||
* Converts an UTF-8 array into a [String]. Replaces invalid input sequences with a default character.
|
||||
*/
|
||||
public fun ByteArray.stringFromUtf8(start: Int = 0, size: Int = this.size) : String =
|
||||
stringFromUtf8Impl(start, size)
|
||||
public fun ByteArray.stringFromUtf8(start: Int = 0, size: Int = this.size) : String {
|
||||
checkBoundsIndexes(start, start + size, this.size)
|
||||
return stringFromUtf8Impl(start, size)
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_ByteArray_stringFromUtf8")
|
||||
private external fun ByteArray.stringFromUtf8Impl(start: Int, size: Int) : String
|
||||
internal external fun ByteArray.stringFromUtf8Impl(start: Int, size: Int) : String
|
||||
|
||||
/**
|
||||
* Converts an UTF-8 array into a [String].
|
||||
* @throws [IllegalCharacterConversionException] if the input is invalid.
|
||||
*/
|
||||
public fun ByteArray.stringFromUtf8OrThrow(start: Int = 0, size: Int = this.size) : String =
|
||||
stringFromUtf8OrThrowImpl(start, size)
|
||||
@UseExperimental(ExperimentalStdlibApi::class)
|
||||
public fun ByteArray.stringFromUtf8OrThrow(start: Int = 0, size: Int = this.size) : String {
|
||||
checkBoundsIndexes(start, start + size, this.size)
|
||||
try {
|
||||
return stringFromUtf8OrThrowImpl(start, size)
|
||||
} catch (e: CharacterCodingException) {
|
||||
throw IllegalCharacterConversionException()
|
||||
}
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_ByteArray_stringFromUtf8OrThrow")
|
||||
private external fun ByteArray.stringFromUtf8OrThrowImpl(start: Int, size: Int) : String
|
||||
internal external fun ByteArray.stringFromUtf8OrThrowImpl(start: Int, size: Int) : String
|
||||
|
||||
/**
|
||||
* Converts a [String] into an UTF-8 array. Replaces invalid input sequences with a default character.
|
||||
*/
|
||||
public fun String.toUtf8(start: Int = 0, size: Int = this.length) : ByteArray =
|
||||
toUtf8Impl(start, size)
|
||||
public fun String.toUtf8(start: Int = 0, size: Int = this.length) : ByteArray {
|
||||
checkBoundsIndexes(start, start + size, this.length)
|
||||
return toUtf8Impl(start, size)
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_String_toUtf8")
|
||||
private external fun String.toUtf8Impl(start: Int, size: Int) : ByteArray
|
||||
internal external fun String.toUtf8Impl(start: Int, size: Int) : ByteArray
|
||||
|
||||
/**
|
||||
* Converts a [String] into an UTF-8 array.
|
||||
* @throws [IllegalCharacterConversionException] if the input is invalid.
|
||||
*/
|
||||
public fun String.toUtf8OrThrow(start: Int = 0, size: Int = this.length) : ByteArray =
|
||||
toUtf8OrThrowImpl(start, size)
|
||||
@UseExperimental(ExperimentalStdlibApi::class)
|
||||
public fun String.toUtf8OrThrow(start: Int = 0, size: Int = this.length) : ByteArray {
|
||||
checkBoundsIndexes(start, start + size, this.length)
|
||||
try {
|
||||
return toUtf8OrThrowImpl(start, size)
|
||||
} catch (e: CharacterCodingException) {
|
||||
throw IllegalCharacterConversionException()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun checkBoundsIndexes(startIndex: Int, endIndex: Int, size: Int) {
|
||||
if (startIndex < 0 || endIndex > size) {
|
||||
throw IndexOutOfBoundsException("startIndex: $startIndex, endIndex: $endIndex, size: $size")
|
||||
}
|
||||
if (startIndex > endIndex) {
|
||||
throw IllegalArgumentException("startIndex: $startIndex > endIndex: $endIndex")
|
||||
}
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_String_toUtf8OrThrow")
|
||||
private external fun String.toUtf8OrThrowImpl(start: Int, size: Int) : ByteArray
|
||||
internal external fun String.toUtf8OrThrowImpl(start: Int, size: Int) : ByteArray
|
||||
|
||||
@SymbolName("Kotlin_String_fromCharArray")
|
||||
internal external fun fromCharArray(array: CharArray, start: Int, size: Int) : String
|
||||
|
||||
@@ -70,8 +70,9 @@ internal fun ThrowNotImplementedError(): Nothing {
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun ThrowIllegalCharacterConversionException(): Nothing {
|
||||
throw IllegalCharacterConversionException()
|
||||
internal fun ThrowCharacterCodingException(): Nothing {
|
||||
@UseExperimental(ExperimentalStdlibApi::class)
|
||||
throw CharacterCodingException()
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package kotlin.text
|
||||
|
||||
/**
|
||||
* The exception thrown when a character encoding or decoding error occurs.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public actual open class CharacterCodingException(message: String?) : Exception(message) {
|
||||
actual constructor() : this(null)
|
||||
}
|
||||
@@ -175,10 +175,12 @@ public actual external fun String.toUpperCase(): String
|
||||
public actual external fun String.toLowerCase(): String
|
||||
|
||||
/**
|
||||
* Returns a new character array containing the characters from this string.
|
||||
* Returns a [CharArray] containing characters of this string.
|
||||
*/
|
||||
public actual fun String.toCharArray(): CharArray = toCharArray(this, 0, length)
|
||||
|
||||
@SymbolName("Kotlin_String_toCharArray")
|
||||
public external fun String.toCharArray(): CharArray
|
||||
private external fun toCharArray(string: String, start: Int, size: Int): CharArray
|
||||
|
||||
/**
|
||||
* Returns a copy of this string having its first letter uppercased, or the original string,
|
||||
@@ -228,7 +230,111 @@ public actual fun String(chars: CharArray): String = fromCharArray(chars, 0, cha
|
||||
* @throws IndexOutOfBoundsException if either [offset] or [length] are less than zero
|
||||
* or `offset + length` is out of [chars] array bounds.
|
||||
*/
|
||||
public actual fun String(chars: CharArray, offset: Int, length: Int): String = fromCharArray(chars, offset, length)
|
||||
public actual fun String(chars: CharArray, offset: Int, length: Int): String {
|
||||
if (offset < 0 || length < 0 || offset + length > chars.size)
|
||||
throw ArrayIndexOutOfBoundsException()
|
||||
|
||||
return fromCharArray(chars, offset, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates characters in this [CharArray] into a String.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public actual fun CharArray.concatToString(): String = fromCharArray(this, 0, size)
|
||||
|
||||
/**
|
||||
* Concatenates characters in this [CharArray] or its subrange into a String.
|
||||
*
|
||||
* @param startIndex the beginning (inclusive) of the subrange of characters, 0 by default.
|
||||
* @param endIndex the end (exclusive) of the subrange of characters, size of this array by default.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the size of this array.
|
||||
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public actual fun CharArray.concatToString(startIndex: Int, endIndex: Int): String {
|
||||
checkBoundsIndexes(startIndex, endIndex, size)
|
||||
return fromCharArray(this, startIndex, endIndex - startIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [CharArray] containing characters of this string or its substring.
|
||||
*
|
||||
* @param startIndex the beginning (inclusive) of the substring, 0 by default.
|
||||
* @param endIndex the end (exclusive) of the substring, length of this string by default.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the length of this string.
|
||||
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public actual fun String.toCharArray(startIndex: Int, endIndex: Int): CharArray {
|
||||
checkBoundsIndexes(startIndex, endIndex, length)
|
||||
return toCharArray(this, startIndex, endIndex - startIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a string from the bytes in UTF-8 encoding in this array.
|
||||
*
|
||||
* Malformed byte sequences are replaced by the replacement char `\uFFFD`.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public actual fun ByteArray.decodeToString(): String = stringFromUtf8Impl(0, size)
|
||||
|
||||
/**
|
||||
* Decodes a string from the bytes in UTF-8 encoding in this array or its subrange.
|
||||
*
|
||||
* @param startIndex the beginning (inclusive) of the subrange to decode, 0 by default.
|
||||
* @param endIndex the end (exclusive) of the subrange to decode, size of this array by default.
|
||||
* @param throwOnInvalidSequence specifies whether to throw an exception on malformed byte sequence or replace it by the replacement char `\uFFFD`.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the size of this array.
|
||||
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
|
||||
* @throws CharacterCodingException if the byte array contains malformed UTF-8 byte sequence and [throwOnInvalidSequence] is true.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public actual fun ByteArray.decodeToString(startIndex: Int, endIndex: Int, throwOnInvalidSequence: Boolean): String {
|
||||
checkBoundsIndexes(startIndex, endIndex, size)
|
||||
return if (throwOnInvalidSequence)
|
||||
stringFromUtf8OrThrowImpl(startIndex, endIndex - startIndex)
|
||||
else
|
||||
stringFromUtf8Impl(startIndex, endIndex - startIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes this string to an array of bytes in UTF-8 encoding.
|
||||
*
|
||||
* Any malformed char sequence is replaced by the replacement byte sequence.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public actual fun String.encodeToByteArray(): ByteArray = toUtf8Impl(0, length)
|
||||
|
||||
/**
|
||||
* Encodes this string or its substring to an array of bytes in UTF-8 encoding.
|
||||
*
|
||||
* @param startIndex the beginning (inclusive) of the substring to encode, 0 by default.
|
||||
* @param endIndex the end (exclusive) of the substring to encode, length of this string by default.
|
||||
* @param throwOnInvalidSequence specifies whether to throw an exception on malformed char sequence or replace.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the length of this string.
|
||||
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
|
||||
* @throws CharacterCodingException if this string contains malformed char sequence and [throwOnInvalidSequence] is true.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public actual fun String.encodeToByteArray(startIndex: Int, endIndex: Int, throwOnInvalidSequence: Boolean): ByteArray {
|
||||
checkBoundsIndexes(startIndex, endIndex, length)
|
||||
return if (throwOnInvalidSequence)
|
||||
toUtf8OrThrowImpl(startIndex, endIndex - startIndex)
|
||||
else
|
||||
toUtf8Impl(startIndex, endIndex - startIndex)
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_String_compareToIgnoreCase")
|
||||
internal external fun compareToIgnoreCase(thiz: String, other: String): Int
|
||||
@@ -241,4 +347,4 @@ public actual fun String.compareTo(other: String, ignoreCase: Boolean): Int {
|
||||
private val STRING_CASE_INSENSITIVE_ORDER = Comparator<String> { a, b -> a.compareTo(b, ignoreCase = true) }
|
||||
|
||||
public actual val String.Companion.CASE_INSENSITIVE_ORDER: Comparator<String>
|
||||
get() = STRING_CASE_INSENSITIVE_ORDER
|
||||
get() = STRING_CASE_INSENSITIVE_ORDER
|
||||
|
||||
Reference in New Issue
Block a user