Implement String to/from ByteArray conversion (KT-24810)

This commit is contained in:
Abduqodiri Qurbonzoda
2019-04-11 03:12:29 +03:00
parent 81d2d3cb6a
commit c8a4fa58cd
15 changed files with 844 additions and 7 deletions
@@ -11,3 +11,10 @@ package kotlin.text
@Suppress("ACTUAL_WITHOUT_EXPECT") // TODO: some supertypes are missing
@SinceKotlin("1.1") public actual typealias StringBuilder = java.lang.StringBuilder
/**
* The exception thrown when a character encoding or decoding error occurs.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual typealias CharacterCodingException = java.nio.charset.CharacterCodingException
@@ -9,7 +9,10 @@
package kotlin.text
import java.nio.ByteBuffer
import java.nio.CharBuffer
import java.nio.charset.Charset
import java.nio.charset.CodingErrorAction
import java.util.Locale
import java.util.regex.Pattern
@@ -142,6 +145,75 @@ public actual fun String.toCharArray(startIndex: Int = 0, endIndex: Int = this.l
return toCharArray(CharArray(endIndex - startIndex), 0, startIndex, endIndex)
}
/**
* 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")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
@ExperimentalStdlibApi
public actual fun ByteArray.decodeToString(
startIndex: Int = 0,
endIndex: Int = this.size,
throwOnInvalidSequence: Boolean = false
): String {
AbstractList.checkBoundsIndexes(startIndex, endIndex, this.size)
if (!throwOnInvalidSequence) {
return String(this, startIndex, endIndex - startIndex)
}
val decoder = Charsets.UTF_8.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT)
return decoder.decode(ByteBuffer.wrap(this, startIndex, endIndex - startIndex)).toString()
}
/**
* 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")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
@ExperimentalStdlibApi
public actual fun String.encodeToByteArray(
startIndex: Int = 0,
endIndex: Int = this.length,
throwOnInvalidSequence: Boolean = false
): ByteArray {
AbstractList.checkBoundsIndexes(startIndex, endIndex, length)
if (!throwOnInvalidSequence) {
return this.substring(startIndex, endIndex).toByteArray(Charsets.UTF_8)
}
val encoder = Charsets.UTF_8.newEncoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT)
val byteBuffer = encoder.encode(CharBuffer.wrap(this, startIndex, endIndex))
return if (byteBuffer.hasArray() && byteBuffer.arrayOffset() == 0 && byteBuffer.remaining() == byteBuffer.array()!!.size) {
byteBuffer.array()
} else {
ByteArray(byteBuffer.remaining()).also { byteBuffer.get(it) }
}
}
/**
* Returns a new character array containing the characters from this string.
*/
@@ -16,3 +16,12 @@ private val isJava6 = System.getProperty("java.version").startsWith("1.6.")
internal actual fun String.removeLeadingPlusOnJava6(): String =
if (isJava6) removePrefix("+") else this
private val isJava7 = System.getProperty("java.version").startsWith("1.7.")
private val isJava8AndAbove = !isJava6 && !isJava7
internal actual inline fun testOnNonJvm6And7(f: () -> Unit) {
if (isJava8AndAbove) {
f()
}
}
@@ -0,0 +1,11 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package test.text
internal actual val surrogateCodePointDecoding: String = ""
internal actual val surrogateCharEncoding: ByteArray = byteArrayOf(0x3F)