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

com.bloomberg.selekt.commons.NativeResources.kt Maven / Gradle / Ivy

/*
 * Copyright 2020 Bloomberg Finance L.P.
 *
 * 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
 *
 *     https://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.bloomberg.selekt.commons

import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.nio.file.Files
import java.util.Locale
import kotlin.io.path.Path
import kotlin.io.path.createTempFile
import kotlin.jvm.Throws

private const val LIBRARY_PATH_KEY = "com.bloomberg.selekt.library_path"

@Suppress("Detekt.StringLiteralDuplication")
@JvmSynthetic
internal fun osNames(systemOsName: String = System.getProperty("os.name")) = systemOsName.lowercase(Locale.US).run {
    when {
        startsWith("mac") -> listOf("darwin", "mac", "macos", "osx")
        startsWith("windows") -> listOf("windows")
        else -> listOf(replace("\\s+", "_"))
    }
}

@JvmSynthetic
internal fun platformIdentifiers() = osNames().flatMap {
    val osArch = System.getProperty("os.arch")
    listOf('-', File.separatorChar).map { s -> "$it$s$osArch" } + it
}

@JvmSynthetic
internal fun libraryExtensions() = osNames().map {
    when (it) {
        "darwin", "mac", "osx" -> ".dylib"
        "windows" -> ".dll"
        else -> ".so"
    }
}.toSet()

@JvmSynthetic
internal fun libraryNames(
    parentDirectory: String,
    name: String
) = (platformIdentifiers() * libraryExtensions()).map {
    "$parentDirectory${File.separatorChar}${it.first}${File.separatorChar}lib$name${it.second}"
}

@Throws(IOException::class)
fun loadEmbeddedLibrary(loader: ClassLoader, parentDirectory: String, name: String) {
    val url = checkNotNull(libraryNames(parentDirectory, name).firstNotNullOfOrNull {
        loader.getResource(it)
    }) { "Failed to find resource with name: $name in directory: $parentDirectory" }

    @Suppress("NewApi") // Not used by Android.
    val file = createTempFile("lib$name", "lib").toFile()
    try {
        url.openStream().use { inputStream ->
            FileOutputStream(file).use {
                inputStream.copyTo(it)
            }
        }
        @Suppress("UnsafeDynamicallyLoadedCode")
        System.load(file.absolutePath)
    } finally {
        file.delete()
    }
}

@Suppress("NewApi")
private fun loadLibrary(
    libraryPath: String,
    parentDirectory: String,
    name: String
) {
    val path = libraryNames(parentDirectory, name).map {
        Path(libraryPath, it)
    }.first {
        Files.exists(it)
    }.toAbsolutePath()
    @Suppress("UnsafeDynamicallyLoadedCode")
    System.load(path.toString())
}

@Throws(IOException::class)
fun loadLibrary(
    loader: ClassLoader,
    parentDirectory: String,
    name: String
) {
    when (val libraryPath = System.getProperty(LIBRARY_PATH_KEY)) {
        null -> loadEmbeddedLibrary(loader, parentDirectory, name)
        else -> loadLibrary(libraryPath, parentDirectory, name)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy