All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.appmattus.crypto.internal.bytes.ByteArrayArray.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2022-2024 Appmattus Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.appmattus.crypto.internal.bytes

internal class ByteArrayArray : ByteBuffer {

    private var bytes: MutableList = mutableListOf()
    private var sizes: MutableList = mutableListOf()

    override var size: Int = 0
        private set

    override fun add(value: ByteArray, offset: Int, length: Int) {
        if (length > 0) {
            bytes += value.copyOfRange(offset, offset + length)
            sizes += length
            size += length
        }
    }

    override fun copyOf() = ByteArrayArray().apply {
        for (i in 0 until bytes.size) {
            add(bytes[i].copyOf(), 0, sizes[i])
        }
    }

    /**
     * Returns the array element at the given [index].  This method can be called using the index operator.
     *
     * If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
     * where the behavior is unspecified.
     */
    override operator fun get(index: Int): Byte {
        val pos = position(index)
        return bytes[pos.first][pos.second]
    }

    private fun position(index: Int): Pair {
        var listIndex = 0
        var totalIndex = 0

        if (bytes.size == 0) {
            throw IndexOutOfBoundsException("Index $index out of bounds for length 0")
        }

        while (index >= totalIndex + sizes[listIndex]) {
            totalIndex += sizes[listIndex]
            listIndex++

            if (listIndex >= bytes.size) {
                throw IndexOutOfBoundsException("Index $index out of bounds for length $size")
            }
        }

        return Pair(listIndex, index - totalIndex)
    }

    override fun copyInto(destination: ByteArray, destinationOffset: Int, startIndex: Int, endIndex: Int): ByteArray {
        var destOffset = destinationOffset
        var len = endIndex - startIndex
        var index = startIndex

        while (len > 0) {
            val pos = position(index)

            val available = sizes[pos.first] - pos.second

            if (available >= len) {
                // this array contains all the data we need...
                bytes[pos.first].copyInto(destination, destOffset, pos.second, pos.second + len)
                len = 0
                destOffset += len
                index += len
            } else {
                // partial bytes
                bytes[pos.first].copyInto(destination, destOffset, pos.second, pos.second + available)
                len -= available
                destOffset += available
                index += available
            }
        }

        return destination
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy