diff --git a/common/build.gradle.kts b/common/build.gradle.kts index fd4ed4a6..ad6ae082 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -137,6 +137,7 @@ kotlin { optIn("kotlinx.cinterop.ExperimentalForeignApi") optIn("kotlin.time.ExperimentalTime") optIn("kotlin.experimental.ExperimentalObjCRefinement") + optIn("com.powersync.PowerSyncInternal") } } diff --git a/common/src/commonMain/kotlin/com/powersync/PowerSyncInternal.kt b/common/src/commonMain/kotlin/com/powersync/PowerSyncInternal.kt new file mode 100644 index 00000000..0f2b3694 --- /dev/null +++ b/common/src/commonMain/kotlin/com/powersync/PowerSyncInternal.kt @@ -0,0 +1,12 @@ +package com.powersync + +@RequiresOptIn(message = "This API should not be used outside of PowerSync SDK packages") +@Retention(AnnotationRetention.BINARY) +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.CONSTRUCTOR, + AnnotationTarget.PROPERTY, + AnnotationTarget.VALUE_PARAMETER, +) +public annotation class PowerSyncInternal diff --git a/common/src/jvmMain/kotlin/com/powersync/ConnectionFactory.jvm.kt b/common/src/jvmMain/kotlin/com/powersync/ConnectionFactory.jvm.kt index e6f91923..ebefecda 100644 --- a/common/src/jvmMain/kotlin/com/powersync/ConnectionFactory.jvm.kt +++ b/common/src/jvmMain/kotlin/com/powersync/ConnectionFactory.jvm.kt @@ -5,4 +5,4 @@ import com.powersync.db.runWrapped @Throws(PowerSyncException::class) public actual fun resolvePowerSyncLoadableExtensionPath(): String? = runWrapped { powersyncExtension } -private val powersyncExtension: String by lazy { extractLib("powersync") } +private val powersyncExtension: String by lazy { extractLib(BuildConfig::class,"powersync") } diff --git a/common/src/jvmMain/kotlin/com/powersync/ExtractLib.kt b/common/src/jvmMain/kotlin/com/powersync/ExtractLib.kt index ee7ee44a..b874ca09 100644 --- a/common/src/jvmMain/kotlin/com/powersync/ExtractLib.kt +++ b/common/src/jvmMain/kotlin/com/powersync/ExtractLib.kt @@ -2,10 +2,10 @@ package com.powersync import java.io.File import java.util.UUID +import kotlin.reflect.KClass -private class R - -internal fun extractLib(fileName: String): String { +@PowerSyncInternal +public fun extractLib(reference: KClass<*>, fileName: String): String { val os = System.getProperty("os.name").lowercase() val (prefix, extension) = when { @@ -34,7 +34,7 @@ internal fun extractLib(fileName: String): String { val resourcePath = "/$prefix${fileName}_$arch.$extension" - (R::class.java.getResourceAsStream(resourcePath) ?: error("Resource $resourcePath not found")).use { input -> + (reference.java.getResourceAsStream(resourcePath) ?: error("Resource $resourcePath not found")).use { input -> file.outputStream().use { output -> input.copyTo(output) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4af0337d..55a506be 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ compose = "1.8.2" # This is for the multiplatform compose androidCompose = "2025.08.00" compose-preview = "1.9.0" compose-lifecycle = "2.9.2" -androidxSqlite = "2.6.0" +androidxSqlite = "2.6.1" androidxSplashscreen = "1.0.1" room = "2.8.0" sqldelight = "2.1.0" diff --git a/plugins/build-plugin/src/main/kotlin/com/powersync/compile/ClangCompile.kt b/plugins/build-plugin/src/main/kotlin/com/powersync/compile/ClangCompile.kt index 914e7aef..eb900e33 100644 --- a/plugins/build-plugin/src/main/kotlin/com/powersync/compile/ClangCompile.kt +++ b/plugins/build-plugin/src/main/kotlin/com/powersync/compile/ClangCompile.kt @@ -42,12 +42,7 @@ abstract class ClangCompile : DefaultTask() { @get:Input val xcodeInstallation: Provider - get() = - providers - .exec { - executable("xcode-select") - args("-p") - }.standardOutput.asText + get() = resolveXcode(providers) @TaskAction fun run() { @@ -95,15 +90,7 @@ abstract class ClangCompile : DefaultTask() { "--compile", "-I${include.get().asFile.absolutePath}", inputFile.get().asFile.absolutePath, - "-DHAVE_GETHOSTUUID=0", - "-DSQLITE_ENABLE_DBSTAT_VTAB", - "-DSQLITE_ENABLE_FTS5", - "-DSQLITE_ENABLE_RTREE", - // Used by GRDB - "-DSQLITE_ENABLE_SNAPSHOT", - // Used for GRDB update hook like functionality - "-DSQLITE_ENABLE_SESSION", - "-DSQLITE_ENABLE_PREUPDATE_HOOK", + *sqlite3ClangOptions, // "-O3", "-o", @@ -126,5 +113,26 @@ abstract class ClangCompile : DefaultTask() { const val TVOS_SIMULATOR_SDK = "Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk" const val MACOS_SDK = "Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/" + + val sqlite3ClangOptions = arrayOf( + // Note: Keep in sync with sqlite3multiplecipers/src/jni/CMakeLists.txt + "-DHAVE_GETHOSTUUID=0", + "-DSQLITE_ENABLE_DBSTAT_VTAB", + "-DSQLITE_ENABLE_FTS5", + "-DSQLITE_ENABLE_RTREE", + // Used by GRDB + "-DSQLITE_ENABLE_SNAPSHOT", + // Used for GRDB update hook like functionality + "-DSQLITE_ENABLE_SESSION", + "-DSQLITE_ENABLE_PREUPDATE_HOOK", + ) + + fun resolveXcode(factory: ProviderFactory): Provider { + return factory + .exec { + executable("xcode-select") + args("-p") + }.standardOutput.asText + } } } diff --git a/plugins/build-plugin/src/main/kotlin/com/powersync/compile/UnzipSqlite.kt b/plugins/build-plugin/src/main/kotlin/com/powersync/compile/UnzipSqlite.kt index 65aa1157..af58169e 100644 --- a/plugins/build-plugin/src/main/kotlin/com/powersync/compile/UnzipSqlite.kt +++ b/plugins/build-plugin/src/main/kotlin/com/powersync/compile/UnzipSqlite.kt @@ -16,10 +16,10 @@ abstract class UnzipSqlite: Copy() { @get:OutputDirectory abstract val destination: DirectoryProperty - fun unzipSqlite(src: FileTree, dir: Provider) { + fun unzipSqlite(src: FileTree, dir: Provider, filter: String? = "*/sqlite3.*") { from( src.matching { - include("*/sqlite3.*") + filter?.let { include(it) } exclude { it.isDirectory } diff --git a/settings.gradle.kts b/settings.gradle.kts index 064dd7e2..0ff49f9b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,6 +36,7 @@ include(":core") include(":core-tests-android") include(":integrations:room") include(":static-sqlite-driver") +include(":sqlite3multipleciphers") include(":integrations:sqldelight") include(":integrations:sqldelight-test-database") diff --git a/sqlite3multipleciphers/README.md b/sqlite3multipleciphers/README.md new file mode 100644 index 00000000..e4952dec --- /dev/null +++ b/sqlite3multipleciphers/README.md @@ -0,0 +1,22 @@ +## Building + +Please note that the build currently only runs on macOS. +We use cross-compilation to be able to compile for Windows and Linux. + +For Linux, we use a Docker container to build the extension. To run the build, +first build that image: + +```shell +docker build -t powersync_kotlin_sqlite3mc_build_helper --load src/jni +``` + +To compile for Windows, we use [llvm-mingw](https://github.com/mstorsjo/llvm-mingw), +which needs to be downloaded. + +With all dependencies ready, run the Gradle task: + +```shell +./gradlew sqlite3multipleciphers:jniCompile -PllvmMingw='.../Downloads/llvm-mingw-20251104-ucrt-macos-universal' +``` + +This outputs binaries to `build/jni-build/`. diff --git a/sqlite3multipleciphers/build.gradle.kts b/sqlite3multipleciphers/build.gradle.kts new file mode 100644 index 00000000..7dc18825 --- /dev/null +++ b/sqlite3multipleciphers/build.gradle.kts @@ -0,0 +1,300 @@ +import com.android.build.gradle.tasks.ExternalNativeBuildTask +import com.powersync.compile.ClangCompile +import com.powersync.compile.CreateSqliteCInterop +import com.powersync.compile.UnzipSqlite +import com.powersync.plugins.utils.powersyncTargets +import de.undercouch.gradle.tasks.download.Download +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.konan.target.HostManager +import kotlin.io.path.Path +import kotlin.io.path.absolutePathString + +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.android.library) + alias(libs.plugins.downloadPlugin) + alias(libs.plugins.kotlinter) + id("com.powersync.plugins.sonatype") + id("com.powersync.plugins.sharedbuild") +} + +val sqlite3McVersion = "2.2.4" +val sqlite3BaseVersion = "3.50.4" + +val downloadSqlite3Mc by tasks.registering(Download::class) { + val zipFileName = "sqlite3mc-$sqlite3McVersion.zip" + src("https://github.com/utelle/SQLite3MultipleCiphers/releases/download/v$sqlite3McVersion/sqlite3mc-$sqlite3McVersion-sqlite-$sqlite3BaseVersion-amalgamation.zip") + dest(layout.buildDirectory.dir("downloads").map { it.file(zipFileName) }) + onlyIfNewer(true) + overwrite(false) +} + +val unzipSQLiteSources by tasks.registering(UnzipSqlite::class) { + val zip = downloadSqlite3Mc.map { it.outputs.files.singleFile } + inputs.file(zip) + + unzipSqlite( + src = zipTree(zip), + dir = layout.buildDirectory.dir("downloads/sqlite3mc"), + filter = null, + ) +} + +val hostManager = HostManager() + +fun compileSqlite3McForKotlinNative(target: KotlinNativeTarget): TaskProvider { + val name = target.targetName + val outputDir = layout.buildDirectory.dir("c/$name") + + val sqlite3Obj = outputDir.map { it.file("sqlite3mc.o") } + val archive = outputDir.map { it.file("libsqlite3mc.a") } + + val compileSqlite = tasks.register("${name}CompileSqlite", ClangCompile::class) { + dependsOn(unzipSQLiteSources) + inputs.dir(unzipSQLiteSources.map { it.destinationDir }) + + inputFile.set(unzipSQLiteSources.flatMap { it.destination.file("sqlite3mc_amalgamation.c") }) + konanTarget.set(target.konanTarget.name) + include.set(unzipSQLiteSources.flatMap { it.destination }) + objectFile.set(sqlite3Obj) + } + + val createStaticLibrary = tasks.register("${name}ArchiveSqlite", com.powersync.compile.CreateStaticLibrary::class) { + inputs.file(compileSqlite.map { it.objectFile }) + objects.from(sqlite3Obj) + staticLibrary.set(archive) + } + + val buildCInteropDef = tasks.register("${name}CinteropSqlite", CreateSqliteCInterop::class) { + inputs.file(createStaticLibrary.map { it.staticLibrary }) + + archiveFile.set(archive) + definitionFile.fileProvider(archive.map { File(it.asFile.parentFile, "sqlite3mc.def") }) + } + + return buildCInteropDef +} + +kotlin { + powersyncTargets() + + applyDefaultHierarchyTemplate() + explicitApi() + + sourceSets { + all { + languageSettings.apply { + optIn("kotlin.experimental.ExperimentalNativeApi") + optIn("kotlinx.cinterop.ExperimentalForeignApi") + optIn("kotlinx.cinterop.BetaInteropApi") + optIn("com.powersync.PowerSyncInternal") + } + } + + val jvmAndroidMain by creating { + dependsOn(commonMain.get()) + } + + androidMain { + dependsOn(jvmAndroidMain) + } + + jvmMain { + dependsOn(jvmAndroidMain) + } + + commonMain.dependencies { + api(projects.common) + implementation(libs.androidx.sqlite.sqlite) + } + + commonTest.dependencies { + implementation(libs.kotlin.test) + api(libs.test.kotest.assertions) + } + } + + targets.withType { + if (hostManager.isEnabled(konanTarget)) { + val compileSqlite3 = compileSqlite3McForKotlinNative(this) + + compilations.named("main") { + cinterops.create("sqlite3mc") { + definitionFile.set(compileSqlite3.flatMap { it.definitionFile }) + } + } + } + } +} + +android { + compileOptions { + targetCompatibility = JavaVersion.VERSION_17 + } + + namespace = "com.powersync.encryption" + compileSdk = + libs.versions.android.compileSdk + .get() + .toInt() + defaultConfig { + minSdk = + libs.versions.android.minSdk + .get() + .toInt() +// consumerProguardFiles("proguard-rules.pro") + } + + externalNativeBuild { + cmake { + path("src/jni/CMakeLists.txt") + } + } + + ndkVersion = "27.1.12297006" +} + +tasks.withType { + dependsOn(unzipSQLiteSources) +} + +tasks.named(kotlin.jvm().compilations["main"].processResourcesTaskName) { + from("build/jni-build/") +} + +val xCodeInstallation = ClangCompile.resolveXcode(providers) + +// Tasks to build the JNI shared library for multiple operating systems. +// Since the JNI sources rarely change, we don't run these tasks on every build. Instead, +// we'll publish these sources as one-off releases when needed, and then reference that URL. +enum class JniTarget { + LINUX_ARM, + LINUX_X64, + MACOS_ARM, + MACOS_X64, + WINDOWS_ARM, + WINDOWS_X64, +} + +fun Exec.registerCompileOnHostTask(target: JniTarget, clang: String = "clang", toolchain: String? = null) { + val outputDirectory = layout.buildDirectory.dir("jni-build") + val outputFile = outputDirectory.map { + it.file(when (target) { + JniTarget.LINUX_ARM -> "libsqlite3mc_jni_aarch64.linux.so" + JniTarget.LINUX_X64 -> "libsqlite3mc_jni_x64.linux.so" + JniTarget.MACOS_ARM -> "libsqlite3mc_jni_aarch64.macos.dylib" + JniTarget.MACOS_X64 -> "libsqlite3mc_jni_x64.macos.dylib" + JniTarget.WINDOWS_ARM -> "sqlite3mc_jni_aarch64.dll" + JniTarget.WINDOWS_X64 -> "sqlite3mc_jni_x64.dll" + }) + } + outputs.file(outputFile) + + dependsOn(unzipSQLiteSources) + val sqlite3McSources = unzipSQLiteSources.map { it.destinationDir } + inputs.dir(sqlite3McSources) + + inputs.dir(layout.projectDirectory.dir("src/jni/")) + + doFirst { + outputDirectory.get().asFile.mkdirs() + } + + if (target == JniTarget.LINUX_X64 || target == JniTarget.LINUX_ARM) { + executable = "/opt/homebrew/bin/docker" + args( + "run", + "-v", "./src:/src", + "-v", "./build:/build", + "powersync_kotlin_sqlite3mc_build_helper", + "clang", + "-fuse-ld=lld" + ) + } else { + executable = clang + } + + val outputFilePath = outputFile.get().asFile.toRelativeString(project.projectDir) + val sourceRoot = sqlite3McSources.get().toRelativeString(project.projectDir) + val amalgamation = File(sourceRoot, "sqlite3mc_amalgamation.c").path + + args( + "-shared", + "-fPIC", + when (target) { + JniTarget.LINUX_ARM -> "--target=aarch64-pc-linux" + JniTarget.LINUX_X64 -> "--target=x86_64-pc-linux" + JniTarget.MACOS_ARM -> "--target=aarch64-apple-macos" + JniTarget.MACOS_X64 -> "--target=x86_64-apple-macos" + JniTarget.WINDOWS_ARM -> "--target=aarch64-w64-mingw32uwp" + JniTarget.WINDOWS_X64 -> "--target=x86_64-w64-mingw32uwp" + }, + "-o", + outputFilePath, + "src/jni/sqlite_bindings.cpp", + amalgamation, + "-I", + sourceRoot, + "-I", + "src/jni/headers/common", + "-I", + when (target) { + JniTarget.LINUX_X64, JniTarget.LINUX_ARM -> "src/jni/headers/inc_linux" + JniTarget.MACOS_X64, JniTarget.MACOS_ARM -> "src/jni/headers/inc_mac" + JniTarget.WINDOWS_X64, JniTarget.WINDOWS_ARM -> "src/jni/headers/inc_win" + }, + "-O3", + *ClangCompile.sqlite3ClangOptions, + ) + + toolchain?.let { args.add(it) } +} + +fun registerCompileMacOsHostTask(arm: Boolean): TaskProvider { + val architecture = if (arm) JniTarget.MACOS_ARM else JniTarget.MACOS_X64 + + return tasks.register("jniCompile${architecture.name}") { + val xcode = Path(xCodeInstallation.get()) + val toolchain = + xcode.resolve("Toolchains/XcodeDefault.xctoolchain/usr/bin").absolutePathString() + registerCompileOnHostTask(architecture, toolchain = toolchain) + } +} + +fun registerCompileWindowsOnMacOsTask(arm: Boolean): TaskProvider { + val architecture = if (arm) JniTarget.WINDOWS_ARM else JniTarget.WINDOWS_X64 + val path = providers.gradleProperty("llvmMingw") + + return tasks.register("jniCompile${architecture.name}") { + val clang = path.orNull?.let { + Path(path.get()).resolve("bin/clang").toString() + } ?: "clang" + + registerCompileOnHostTask(architecture, clang = clang) + } +} + +fun registerCompileLinuxOnMacOsTask(arm: Boolean): TaskProvider { + val architecture = if (arm) JniTarget.LINUX_ARM else JniTarget.LINUX_X64 + + return tasks.register("jniCompile${architecture.name}") { + registerCompileOnHostTask(architecture) + } +} + +val linuxArm64 = registerCompileLinuxOnMacOsTask(true) +val linuxX64 = registerCompileLinuxOnMacOsTask(false) + +val macosArm64 = registerCompileMacOsHostTask(true) +val macosX64 = registerCompileMacOsHostTask(false) + +val windowsArm64 = registerCompileWindowsOnMacOsTask(true) +val windowsX64 = registerCompileWindowsOnMacOsTask(false) + +tasks.register("jniCompile") { + dependsOn(linuxX64, linuxArm64) + dependsOn(macosX64, macosArm64) + dependsOn(windowsX64, macosArm64) +} diff --git a/sqlite3multipleciphers/src/androidMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.android.kt b/sqlite3multipleciphers/src/androidMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.android.kt new file mode 100644 index 00000000..408c8e2d --- /dev/null +++ b/sqlite3multipleciphers/src/androidMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.android.kt @@ -0,0 +1,4 @@ +package com.powersync.encryption + +internal actual fun ensureJniLibraryLoaded() { +} diff --git a/sqlite3multipleciphers/src/commonMain/kotlin/com/powersync/encryption/BaseEncryptedDatabaseFactory.kt b/sqlite3multipleciphers/src/commonMain/kotlin/com/powersync/encryption/BaseEncryptedDatabaseFactory.kt new file mode 100644 index 00000000..5729596f --- /dev/null +++ b/sqlite3multipleciphers/src/commonMain/kotlin/com/powersync/encryption/BaseEncryptedDatabaseFactory.kt @@ -0,0 +1,23 @@ +package com.powersync.encryption + +import androidx.sqlite.SQLiteConnection +import androidx.sqlite.execSQL + +public sealed interface Key { + public class Passphrase(public val passphrase: String) : Key + // TODO: Add raw key api +} + +internal fun SQLiteConnection.encryptOrClose(key: Key) { + try { + when (key) { + is Key.Passphrase -> { + val escaped = key.passphrase.replace("'", "''") + execSQL("pragma key='$escaped'") + } + } + } catch (e: Exception) { + close() + throw e + } +} \ No newline at end of file diff --git a/sqlite3multipleciphers/src/jni/CMakeLists.txt b/sqlite3multipleciphers/src/jni/CMakeLists.txt new file mode 100644 index 00000000..e16b1852 --- /dev/null +++ b/sqlite3multipleciphers/src/jni/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.14) +project( + powersync_sqlite3mc_bundled + VERSION 3 + LANGUAGES C CXX +) + +set(CMAKE_C_FLAGS "-O3") + +add_library(sqlite3mc_bundled SHARED "../../build/downloads/sqlite3mc/sqlite3mc_amalgamation.c" "sqlite_bindings.cpp") +target_include_directories(sqlite3mc_bundled PRIVATE "../../build/downloads/sqlite3mc") + +# Note: Keep in sync with the ClangCompile task used for static-sqlite-driver +target_compile_definitions(sqlite3mc_bundled PUBLIC + HAVE_GETHOSTUUID=0 + SQLITE_ENABLE_DBSTAT_VTAB + SQLITE_ENABLE_FTS5 + SQLITE_ENABLE_RTREE + SQLITE_ENABLE_SNAPSHOT + SQLITE_ENABLE_SESSION + SQLITE_ENABLE_PREUPDATE_HOOK +) diff --git a/sqlite3multipleciphers/src/jni/Dockerfile b/sqlite3multipleciphers/src/jni/Dockerfile new file mode 100644 index 00000000..38eaa02a --- /dev/null +++ b/sqlite3multipleciphers/src/jni/Dockerfile @@ -0,0 +1,3 @@ +FROM ubuntu:latest + +RUN apt update && apt install -y gcc-x86-64-linux-gnu gcc-aarch64-linux-gnu g++-x86-64-linux-gnu g++-aarch64-linux-gnu clang lld diff --git a/sqlite3multipleciphers/src/jni/headers/common/jni.h b/sqlite3multipleciphers/src/jni/headers/common/jni.h new file mode 100644 index 00000000..cff1a02f --- /dev/null +++ b/sqlite3multipleciphers/src/jni/headers/common/jni.h @@ -0,0 +1,1961 @@ +/* + * @(#)jni.h 1.62 06/02/02 + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +/* + * We used part of Netscape's Java Runtime Interface (JRI) as the starting + * point of our design and implementation. + */ + +/****************************************************************************** + * Java Runtime Interface + * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved. + *****************************************************************************/ + +#ifndef _JAVASOFT_JNI_H_ +#define _JAVASOFT_JNI_H_ + +#include +#include + +/* jni_md.h contains the machine-dependent typedefs for jbyte, jint + and jlong */ + +#include "jni_md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * JNI Types + */ + +#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H + +typedef unsigned char jboolean; +typedef unsigned short jchar; +typedef short jshort; +typedef float jfloat; +typedef double jdouble; + +typedef jint jsize; + +#ifdef __cplusplus + +class _jobject {}; +class _jclass : public _jobject {}; +class _jthrowable : public _jobject {}; +class _jstring : public _jobject {}; +class _jarray : public _jobject {}; +class _jbooleanArray : public _jarray {}; +class _jbyteArray : public _jarray {}; +class _jcharArray : public _jarray {}; +class _jshortArray : public _jarray {}; +class _jintArray : public _jarray {}; +class _jlongArray : public _jarray {}; +class _jfloatArray : public _jarray {}; +class _jdoubleArray : public _jarray {}; +class _jobjectArray : public _jarray {}; + +typedef _jobject *jobject; +typedef _jclass *jclass; +typedef _jthrowable *jthrowable; +typedef _jstring *jstring; +typedef _jarray *jarray; +typedef _jbooleanArray *jbooleanArray; +typedef _jbyteArray *jbyteArray; +typedef _jcharArray *jcharArray; +typedef _jshortArray *jshortArray; +typedef _jintArray *jintArray; +typedef _jlongArray *jlongArray; +typedef _jfloatArray *jfloatArray; +typedef _jdoubleArray *jdoubleArray; +typedef _jobjectArray *jobjectArray; + +#else + +struct _jobject; + +typedef struct _jobject *jobject; +typedef jobject jclass; +typedef jobject jthrowable; +typedef jobject jstring; +typedef jobject jarray; +typedef jarray jbooleanArray; +typedef jarray jbyteArray; +typedef jarray jcharArray; +typedef jarray jshortArray; +typedef jarray jintArray; +typedef jarray jlongArray; +typedef jarray jfloatArray; +typedef jarray jdoubleArray; +typedef jarray jobjectArray; + +#endif + +typedef jobject jweak; + +typedef union jvalue { + jboolean z; + jbyte b; + jchar c; + jshort s; + jint i; + jlong j; + jfloat f; + jdouble d; + jobject l; +} jvalue; + +struct _jfieldID; +typedef struct _jfieldID *jfieldID; + +struct _jmethodID; +typedef struct _jmethodID *jmethodID; + +/* Return values from jobjectRefType */ +typedef enum _jobjectType { + JNIInvalidRefType = 0, + JNILocalRefType = 1, + JNIGlobalRefType = 2, + JNIWeakGlobalRefType = 3 +} jobjectRefType; + + +#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */ + +/* + * jboolean constants + */ + +#define JNI_FALSE 0 +#define JNI_TRUE 1 + +/* + * possible return values for JNI functions. + */ + +#define JNI_OK 0 /* success */ +#define JNI_ERR (-1) /* unknown error */ +#define JNI_EDETACHED (-2) /* thread detached from the VM */ +#define JNI_EVERSION (-3) /* JNI version error */ +#define JNI_ENOMEM (-4) /* not enough memory */ +#define JNI_EEXIST (-5) /* VM already created */ +#define JNI_EINVAL (-6) /* invalid arguments */ + +/* + * used in ReleaseScalarArrayElements + */ + +#define JNI_COMMIT 1 +#define JNI_ABORT 2 + +/* + * used in RegisterNatives to describe native method name, signature, + * and function pointer. + */ + +typedef struct { + char *name; + char *signature; + void *fnPtr; +} JNINativeMethod; + +/* + * JNI Native Method Interface. + */ + +struct JNINativeInterface_; + +struct JNIEnv_; + +#ifdef __cplusplus +typedef JNIEnv_ JNIEnv; +#else +typedef const struct JNINativeInterface_ *JNIEnv; +#endif + +/* + * JNI Invocation Interface. + */ + +struct JNIInvokeInterface_; + +struct JavaVM_; + +#ifdef __cplusplus +typedef JavaVM_ JavaVM; +#else +typedef const struct JNIInvokeInterface_ *JavaVM; +#endif + +struct JNINativeInterface_ { + void *reserved0; + void *reserved1; + void *reserved2; + + void *reserved3; + +#if !TARGET_RT_MAC_CFM && defined(__ppc__) + void* cfm_vectors[225]; +#endif /* !TARGET_RT_MAC_CFM && defined(__ppc__) */ + + jint (JNICALL *GetVersion)(JNIEnv *env); + + jclass (JNICALL *DefineClass) + (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, + jsize len); + jclass (JNICALL *FindClass) + (JNIEnv *env, const char *name); + + jmethodID (JNICALL *FromReflectedMethod) + (JNIEnv *env, jobject method); + jfieldID (JNICALL *FromReflectedField) + (JNIEnv *env, jobject field); + + jobject (JNICALL *ToReflectedMethod) + (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); + + jclass (JNICALL *GetSuperclass) + (JNIEnv *env, jclass sub); + jboolean (JNICALL *IsAssignableFrom) + (JNIEnv *env, jclass sub, jclass sup); + + jobject (JNICALL *ToReflectedField) + (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); + + jint (JNICALL *Throw) + (JNIEnv *env, jthrowable obj); + jint (JNICALL *ThrowNew) + (JNIEnv *env, jclass clazz, const char *msg); + jthrowable (JNICALL *ExceptionOccurred) + (JNIEnv *env); + void (JNICALL *ExceptionDescribe) + (JNIEnv *env); + void (JNICALL *ExceptionClear) + (JNIEnv *env); + void (JNICALL *FatalError) + (JNIEnv *env, const char *msg); + + jint (JNICALL *PushLocalFrame) + (JNIEnv *env, jint capacity); + jobject (JNICALL *PopLocalFrame) + (JNIEnv *env, jobject result); + + jobject (JNICALL *NewGlobalRef) + (JNIEnv *env, jobject lobj); + void (JNICALL *DeleteGlobalRef) + (JNIEnv *env, jobject gref); + void (JNICALL *DeleteLocalRef) + (JNIEnv *env, jobject obj); + jboolean (JNICALL *IsSameObject) + (JNIEnv *env, jobject obj1, jobject obj2); + jobject (JNICALL *NewLocalRef) + (JNIEnv *env, jobject ref); + jint (JNICALL *EnsureLocalCapacity) + (JNIEnv *env, jint capacity); + + jobject (JNICALL *AllocObject) + (JNIEnv *env, jclass clazz); + jobject (JNICALL *NewObject) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *NewObjectV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jobject (JNICALL *NewObjectA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jclass (JNICALL *GetObjectClass) + (JNIEnv *env, jobject obj); + jboolean (JNICALL *IsInstanceOf) + (JNIEnv *env, jobject obj, jclass clazz); + + jmethodID (JNICALL *GetMethodID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *CallObjectMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jobject (JNICALL *CallObjectMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jobject (JNICALL *CallObjectMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jboolean (JNICALL *CallBooleanMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jboolean (JNICALL *CallBooleanMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jboolean (JNICALL *CallBooleanMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jbyte (JNICALL *CallByteMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jbyte (JNICALL *CallByteMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jbyte (JNICALL *CallByteMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jchar (JNICALL *CallCharMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jchar (JNICALL *CallCharMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jchar (JNICALL *CallCharMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jshort (JNICALL *CallShortMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jshort (JNICALL *CallShortMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jshort (JNICALL *CallShortMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jint (JNICALL *CallIntMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jint (JNICALL *CallIntMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jint (JNICALL *CallIntMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jlong (JNICALL *CallLongMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jlong (JNICALL *CallLongMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jlong (JNICALL *CallLongMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jfloat (JNICALL *CallFloatMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jfloat (JNICALL *CallFloatMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jfloat (JNICALL *CallFloatMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jdouble (JNICALL *CallDoubleMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jdouble (JNICALL *CallDoubleMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jdouble (JNICALL *CallDoubleMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + void (JNICALL *CallVoidMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + void (JNICALL *CallVoidMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + void (JNICALL *CallVoidMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jobject (JNICALL *CallNonvirtualObjectMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *CallNonvirtualObjectMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jobject (JNICALL *CallNonvirtualObjectMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jboolean (JNICALL *CallNonvirtualBooleanMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jboolean (JNICALL *CallNonvirtualBooleanMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jboolean (JNICALL *CallNonvirtualBooleanMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jbyte (JNICALL *CallNonvirtualByteMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jbyte (JNICALL *CallNonvirtualByteMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jbyte (JNICALL *CallNonvirtualByteMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jchar (JNICALL *CallNonvirtualCharMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jchar (JNICALL *CallNonvirtualCharMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jchar (JNICALL *CallNonvirtualCharMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jshort (JNICALL *CallNonvirtualShortMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jshort (JNICALL *CallNonvirtualShortMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jshort (JNICALL *CallNonvirtualShortMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jint (JNICALL *CallNonvirtualIntMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jint (JNICALL *CallNonvirtualIntMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jint (JNICALL *CallNonvirtualIntMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jlong (JNICALL *CallNonvirtualLongMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jlong (JNICALL *CallNonvirtualLongMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jlong (JNICALL *CallNonvirtualLongMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jfloat (JNICALL *CallNonvirtualFloatMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jfloat (JNICALL *CallNonvirtualFloatMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jfloat (JNICALL *CallNonvirtualFloatMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jdouble (JNICALL *CallNonvirtualDoubleMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jdouble (JNICALL *CallNonvirtualDoubleMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jdouble (JNICALL *CallNonvirtualDoubleMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + void (JNICALL *CallNonvirtualVoidMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + void (JNICALL *CallNonvirtualVoidMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + void (JNICALL *CallNonvirtualVoidMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jfieldID (JNICALL *GetFieldID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *GetObjectField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jboolean (JNICALL *GetBooleanField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jbyte (JNICALL *GetByteField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jchar (JNICALL *GetCharField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jshort (JNICALL *GetShortField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jint (JNICALL *GetIntField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jlong (JNICALL *GetLongField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jfloat (JNICALL *GetFloatField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jdouble (JNICALL *GetDoubleField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + + void (JNICALL *SetObjectField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); + void (JNICALL *SetBooleanField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); + void (JNICALL *SetByteField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); + void (JNICALL *SetCharField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); + void (JNICALL *SetShortField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); + void (JNICALL *SetIntField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jint val); + void (JNICALL *SetLongField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); + void (JNICALL *SetFloatField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); + void (JNICALL *SetDoubleField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); + + jmethodID (JNICALL *GetStaticMethodID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *CallStaticObjectMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *CallStaticObjectMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jobject (JNICALL *CallStaticObjectMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jboolean (JNICALL *CallStaticBooleanMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jboolean (JNICALL *CallStaticBooleanMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jboolean (JNICALL *CallStaticBooleanMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jbyte (JNICALL *CallStaticByteMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jbyte (JNICALL *CallStaticByteMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jbyte (JNICALL *CallStaticByteMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jchar (JNICALL *CallStaticCharMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jchar (JNICALL *CallStaticCharMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jchar (JNICALL *CallStaticCharMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jshort (JNICALL *CallStaticShortMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jshort (JNICALL *CallStaticShortMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jshort (JNICALL *CallStaticShortMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jint (JNICALL *CallStaticIntMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jint (JNICALL *CallStaticIntMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jint (JNICALL *CallStaticIntMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jlong (JNICALL *CallStaticLongMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jlong (JNICALL *CallStaticLongMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jlong (JNICALL *CallStaticLongMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jfloat (JNICALL *CallStaticFloatMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jfloat (JNICALL *CallStaticFloatMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jfloat (JNICALL *CallStaticFloatMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jdouble (JNICALL *CallStaticDoubleMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jdouble (JNICALL *CallStaticDoubleMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jdouble (JNICALL *CallStaticDoubleMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + void (JNICALL *CallStaticVoidMethod) + (JNIEnv *env, jclass cls, jmethodID methodID, ...); + void (JNICALL *CallStaticVoidMethodV) + (JNIEnv *env, jclass cls, jmethodID methodID, va_list args); + void (JNICALL *CallStaticVoidMethodA) + (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args); + + jfieldID (JNICALL *GetStaticFieldID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + jobject (JNICALL *GetStaticObjectField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jboolean (JNICALL *GetStaticBooleanField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jbyte (JNICALL *GetStaticByteField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jchar (JNICALL *GetStaticCharField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jshort (JNICALL *GetStaticShortField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jint (JNICALL *GetStaticIntField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jlong (JNICALL *GetStaticLongField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jfloat (JNICALL *GetStaticFloatField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jdouble (JNICALL *GetStaticDoubleField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + + void (JNICALL *SetStaticObjectField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value); + void (JNICALL *SetStaticBooleanField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value); + void (JNICALL *SetStaticByteField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value); + void (JNICALL *SetStaticCharField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value); + void (JNICALL *SetStaticShortField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value); + void (JNICALL *SetStaticIntField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value); + void (JNICALL *SetStaticLongField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value); + void (JNICALL *SetStaticFloatField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value); + void (JNICALL *SetStaticDoubleField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value); + + jstring (JNICALL *NewString) + (JNIEnv *env, const jchar *unicode, jsize len); + jsize (JNICALL *GetStringLength) + (JNIEnv *env, jstring str); + const jchar *(JNICALL *GetStringChars) + (JNIEnv *env, jstring str, jboolean *isCopy); + void (JNICALL *ReleaseStringChars) + (JNIEnv *env, jstring str, const jchar *chars); + + jstring (JNICALL *NewStringUTF) + (JNIEnv *env, const char *utf); + jsize (JNICALL *GetStringUTFLength) + (JNIEnv *env, jstring str); + const char* (JNICALL *GetStringUTFChars) + (JNIEnv *env, jstring str, jboolean *isCopy); + void (JNICALL *ReleaseStringUTFChars) + (JNIEnv *env, jstring str, const char* chars); + + + jsize (JNICALL *GetArrayLength) + (JNIEnv *env, jarray array); + + jobjectArray (JNICALL *NewObjectArray) + (JNIEnv *env, jsize len, jclass clazz, jobject init); + jobject (JNICALL *GetObjectArrayElement) + (JNIEnv *env, jobjectArray array, jsize index); + void (JNICALL *SetObjectArrayElement) + (JNIEnv *env, jobjectArray array, jsize index, jobject val); + + jbooleanArray (JNICALL *NewBooleanArray) + (JNIEnv *env, jsize len); + jbyteArray (JNICALL *NewByteArray) + (JNIEnv *env, jsize len); + jcharArray (JNICALL *NewCharArray) + (JNIEnv *env, jsize len); + jshortArray (JNICALL *NewShortArray) + (JNIEnv *env, jsize len); + jintArray (JNICALL *NewIntArray) + (JNIEnv *env, jsize len); + jlongArray (JNICALL *NewLongArray) + (JNIEnv *env, jsize len); + jfloatArray (JNICALL *NewFloatArray) + (JNIEnv *env, jsize len); + jdoubleArray (JNICALL *NewDoubleArray) + (JNIEnv *env, jsize len); + + jboolean * (JNICALL *GetBooleanArrayElements) + (JNIEnv *env, jbooleanArray array, jboolean *isCopy); + jbyte * (JNICALL *GetByteArrayElements) + (JNIEnv *env, jbyteArray array, jboolean *isCopy); + jchar * (JNICALL *GetCharArrayElements) + (JNIEnv *env, jcharArray array, jboolean *isCopy); + jshort * (JNICALL *GetShortArrayElements) + (JNIEnv *env, jshortArray array, jboolean *isCopy); + jint * (JNICALL *GetIntArrayElements) + (JNIEnv *env, jintArray array, jboolean *isCopy); + jlong * (JNICALL *GetLongArrayElements) + (JNIEnv *env, jlongArray array, jboolean *isCopy); + jfloat * (JNICALL *GetFloatArrayElements) + (JNIEnv *env, jfloatArray array, jboolean *isCopy); + jdouble * (JNICALL *GetDoubleArrayElements) + (JNIEnv *env, jdoubleArray array, jboolean *isCopy); + + void (JNICALL *ReleaseBooleanArrayElements) + (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode); + void (JNICALL *ReleaseByteArrayElements) + (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode); + void (JNICALL *ReleaseCharArrayElements) + (JNIEnv *env, jcharArray array, jchar *elems, jint mode); + void (JNICALL *ReleaseShortArrayElements) + (JNIEnv *env, jshortArray array, jshort *elems, jint mode); + void (JNICALL *ReleaseIntArrayElements) + (JNIEnv *env, jintArray array, jint *elems, jint mode); + void (JNICALL *ReleaseLongArrayElements) + (JNIEnv *env, jlongArray array, jlong *elems, jint mode); + void (JNICALL *ReleaseFloatArrayElements) + (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode); + void (JNICALL *ReleaseDoubleArrayElements) + (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode); + + void (JNICALL *GetBooleanArrayRegion) + (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); + void (JNICALL *GetByteArrayRegion) + (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); + void (JNICALL *GetCharArrayRegion) + (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); + void (JNICALL *GetShortArrayRegion) + (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); + void (JNICALL *GetIntArrayRegion) + (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); + void (JNICALL *GetLongArrayRegion) + (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); + void (JNICALL *GetFloatArrayRegion) + (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); + void (JNICALL *GetDoubleArrayRegion) + (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); + + void (JNICALL *SetBooleanArrayRegion) + (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf); + void (JNICALL *SetByteArrayRegion) + (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf); + void (JNICALL *SetCharArrayRegion) + (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf); + void (JNICALL *SetShortArrayRegion) + (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf); + void (JNICALL *SetIntArrayRegion) + (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf); + void (JNICALL *SetLongArrayRegion) + (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf); + void (JNICALL *SetFloatArrayRegion) + (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf); + void (JNICALL *SetDoubleArrayRegion) + (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf); + + jint (JNICALL *RegisterNatives) + (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, + jint nMethods); + jint (JNICALL *UnregisterNatives) + (JNIEnv *env, jclass clazz); + + jint (JNICALL *MonitorEnter) + (JNIEnv *env, jobject obj); + jint (JNICALL *MonitorExit) + (JNIEnv *env, jobject obj); + + jint (JNICALL *GetJavaVM) + (JNIEnv *env, JavaVM **vm); + + void (JNICALL *GetStringRegion) + (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); + void (JNICALL *GetStringUTFRegion) + (JNIEnv *env, jstring str, jsize start, jsize len, char *buf); + + void * (JNICALL *GetPrimitiveArrayCritical) + (JNIEnv *env, jarray array, jboolean *isCopy); + void (JNICALL *ReleasePrimitiveArrayCritical) + (JNIEnv *env, jarray array, void *carray, jint mode); + + const jchar * (JNICALL *GetStringCritical) + (JNIEnv *env, jstring string, jboolean *isCopy); + void (JNICALL *ReleaseStringCritical) + (JNIEnv *env, jstring string, const jchar *cstring); + + jweak (JNICALL *NewWeakGlobalRef) + (JNIEnv *env, jobject obj); + void (JNICALL *DeleteWeakGlobalRef) + (JNIEnv *env, jweak ref); + + jboolean (JNICALL *ExceptionCheck) + (JNIEnv *env); + + jobject (JNICALL *NewDirectByteBuffer) + (JNIEnv* env, void* address, jlong capacity); + void* (JNICALL *GetDirectBufferAddress) + (JNIEnv* env, jobject buf); + jlong (JNICALL *GetDirectBufferCapacity) + (JNIEnv* env, jobject buf); + + /* New JNI 1.6 Features */ + + jobjectRefType (JNICALL *GetObjectRefType) + (JNIEnv* env, jobject obj); + + #if TARGET_RT_MAC_CFM && defined(__ppc__) + void* real_functions[228]; + #endif /* TARGET_RT_MAC_CFM && defined(__ppc__) */ +}; + +/* + * We use inlined functions for C++ so that programmers can write: + * + * env->FindClass("java/lang/String") + * + * in C++ rather than: + * + * (*env)->FindClass(env, "java/lang/String") + * + * in C. + */ + +struct JNIEnv_ { + const struct JNINativeInterface_ *functions; +#ifdef __cplusplus + + jint GetVersion() { + return functions->GetVersion(this); + } + jclass DefineClass(const char *name, jobject loader, const jbyte *buf, + jsize len) { + return functions->DefineClass(this, name, loader, buf, len); + } + jclass FindClass(const char *name) { + return functions->FindClass(this, name); + } + jmethodID FromReflectedMethod(jobject method) { + return functions->FromReflectedMethod(this,method); + } + jfieldID FromReflectedField(jobject field) { + return functions->FromReflectedField(this,field); + } + + jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { + return functions->ToReflectedMethod(this, cls, methodID, isStatic); + } + + jclass GetSuperclass(jclass sub) { + return functions->GetSuperclass(this, sub); + } + jboolean IsAssignableFrom(jclass sub, jclass sup) { + return functions->IsAssignableFrom(this, sub, sup); + } + + jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) { + return functions->ToReflectedField(this,cls,fieldID,isStatic); + } + + jint Throw(jthrowable obj) { + return functions->Throw(this, obj); + } + jint ThrowNew(jclass clazz, const char *msg) { + return functions->ThrowNew(this, clazz, msg); + } + jthrowable ExceptionOccurred() { + return functions->ExceptionOccurred(this); + } + void ExceptionDescribe() { + functions->ExceptionDescribe(this); + } + void ExceptionClear() { + functions->ExceptionClear(this); + } + void FatalError(const char *msg) { + functions->FatalError(this, msg); + } + + jint PushLocalFrame(jint capacity) { + return functions->PushLocalFrame(this,capacity); + } + jobject PopLocalFrame(jobject result) { + return functions->PopLocalFrame(this,result); + } + + jobject NewGlobalRef(jobject lobj) { + return functions->NewGlobalRef(this,lobj); + } + void DeleteGlobalRef(jobject gref) { + functions->DeleteGlobalRef(this,gref); + } + void DeleteLocalRef(jobject obj) { + functions->DeleteLocalRef(this, obj); + } + + jboolean IsSameObject(jobject obj1, jobject obj2) { + return functions->IsSameObject(this,obj1,obj2); + } + + jobject NewLocalRef(jobject ref) { + return functions->NewLocalRef(this,ref); + } + jint EnsureLocalCapacity(jint capacity) { + return functions->EnsureLocalCapacity(this,capacity); + } + + jobject AllocObject(jclass clazz) { + return functions->AllocObject(this,clazz); + } + jobject NewObject(jclass clazz, jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args, methodID); + result = functions->NewObjectV(this,clazz,methodID,args); + va_end(args); + return result; + } + jobject NewObjectV(jclass clazz, jmethodID methodID, + va_list args) { + return functions->NewObjectV(this,clazz,methodID,args); + } + jobject NewObjectA(jclass clazz, jmethodID methodID, + const jvalue *args) { + return functions->NewObjectA(this,clazz,methodID,args); + } + + jclass GetObjectClass(jobject obj) { + return functions->GetObjectClass(this,obj); + } + jboolean IsInstanceOf(jobject obj, jclass clazz) { + return functions->IsInstanceOf(this,obj,clazz); + } + + jmethodID GetMethodID(jclass clazz, const char *name, + const char *sig) { + return functions->GetMethodID(this,clazz,name,sig); + } + + jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallObjectMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jobject CallObjectMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallObjectMethodV(this,obj,methodID,args); + } + jobject CallObjectMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallObjectMethodA(this,obj,methodID,args); + } + + jboolean CallBooleanMethod(jobject obj, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallBooleanMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallBooleanMethodV(this,obj,methodID,args); + } + jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallBooleanMethodA(this,obj,methodID, args); + } + + jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallByteMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jbyte CallByteMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallByteMethodV(this,obj,methodID,args); + } + jbyte CallByteMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallByteMethodA(this,obj,methodID,args); + } + + jchar CallCharMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallCharMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jchar CallCharMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallCharMethodV(this,obj,methodID,args); + } + jchar CallCharMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallCharMethodA(this,obj,methodID,args); + } + + jshort CallShortMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallShortMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jshort CallShortMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallShortMethodV(this,obj,methodID,args); + } + jshort CallShortMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallShortMethodA(this,obj,methodID,args); + } + + jint CallIntMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallIntMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jint CallIntMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallIntMethodV(this,obj,methodID,args); + } + jint CallIntMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallIntMethodA(this,obj,methodID,args); + } + + jlong CallLongMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallLongMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jlong CallLongMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallLongMethodV(this,obj,methodID,args); + } + jlong CallLongMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallLongMethodA(this,obj,methodID,args); + } + + jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallFloatMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jfloat CallFloatMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallFloatMethodV(this,obj,methodID,args); + } + jfloat CallFloatMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallFloatMethodA(this,obj,methodID,args); + } + + jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallDoubleMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallDoubleMethodV(this,obj,methodID,args); + } + jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallDoubleMethodA(this,obj,methodID,args); + } + + void CallVoidMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallVoidMethodV(this,obj,methodID,args); + va_end(args); + } + void CallVoidMethodV(jobject obj, jmethodID methodID, + va_list args) { + functions->CallVoidMethodV(this,obj,methodID,args); + } + void CallVoidMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + functions->CallVoidMethodA(this,obj,methodID,args); + } + + jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallNonvirtualObjectMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualObjectMethodV(this,obj,clazz, + methodID,args); + } + jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualObjectMethodA(this,obj,clazz, + methodID,args); + } + + jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualBooleanMethodV(this,obj,clazz, + methodID,args); + } + jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualBooleanMethodA(this,obj,clazz, + methodID, args); + } + + jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallNonvirtualByteMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualByteMethodV(this,obj,clazz, + methodID,args); + } + jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualByteMethodA(this,obj,clazz, + methodID,args); + } + + jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallNonvirtualCharMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualCharMethodV(this,obj,clazz, + methodID,args); + } + jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualCharMethodA(this,obj,clazz, + methodID,args); + } + + jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallNonvirtualShortMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualShortMethodV(this,obj,clazz, + methodID,args); + } + jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualShortMethodA(this,obj,clazz, + methodID,args); + } + + jint CallNonvirtualIntMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallNonvirtualIntMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualIntMethodV(this,obj,clazz, + methodID,args); + } + jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualIntMethodA(this,obj,clazz, + methodID,args); + } + + jlong CallNonvirtualLongMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallNonvirtualLongMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualLongMethodV(this,obj,clazz, + methodID,args); + } + jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualLongMethodA(this,obj,clazz, + methodID,args); + } + + jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallNonvirtualFloatMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + return functions->CallNonvirtualFloatMethodV(this,obj,clazz, + methodID,args); + } + jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + return functions->CallNonvirtualFloatMethodA(this,obj,clazz, + methodID,args); + } + + jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + return functions->CallNonvirtualDoubleMethodV(this,obj,clazz, + methodID,args); + } + jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + return functions->CallNonvirtualDoubleMethodA(this,obj,clazz, + methodID,args); + } + + void CallNonvirtualVoidMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); + va_end(args); + } + void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); + } + void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args); + } + + jfieldID GetFieldID(jclass clazz, const char *name, + const char *sig) { + return functions->GetFieldID(this,clazz,name,sig); + } + + jobject GetObjectField(jobject obj, jfieldID fieldID) { + return functions->GetObjectField(this,obj,fieldID); + } + jboolean GetBooleanField(jobject obj, jfieldID fieldID) { + return functions->GetBooleanField(this,obj,fieldID); + } + jbyte GetByteField(jobject obj, jfieldID fieldID) { + return functions->GetByteField(this,obj,fieldID); + } + jchar GetCharField(jobject obj, jfieldID fieldID) { + return functions->GetCharField(this,obj,fieldID); + } + jshort GetShortField(jobject obj, jfieldID fieldID) { + return functions->GetShortField(this,obj,fieldID); + } + jint GetIntField(jobject obj, jfieldID fieldID) { + return functions->GetIntField(this,obj,fieldID); + } + jlong GetLongField(jobject obj, jfieldID fieldID) { + return functions->GetLongField(this,obj,fieldID); + } + jfloat GetFloatField(jobject obj, jfieldID fieldID) { + return functions->GetFloatField(this,obj,fieldID); + } + jdouble GetDoubleField(jobject obj, jfieldID fieldID) { + return functions->GetDoubleField(this,obj,fieldID); + } + + void SetObjectField(jobject obj, jfieldID fieldID, jobject val) { + functions->SetObjectField(this,obj,fieldID,val); + } + void SetBooleanField(jobject obj, jfieldID fieldID, + jboolean val) { + functions->SetBooleanField(this,obj,fieldID,val); + } + void SetByteField(jobject obj, jfieldID fieldID, + jbyte val) { + functions->SetByteField(this,obj,fieldID,val); + } + void SetCharField(jobject obj, jfieldID fieldID, + jchar val) { + functions->SetCharField(this,obj,fieldID,val); + } + void SetShortField(jobject obj, jfieldID fieldID, + jshort val) { + functions->SetShortField(this,obj,fieldID,val); + } + void SetIntField(jobject obj, jfieldID fieldID, + jint val) { + functions->SetIntField(this,obj,fieldID,val); + } + void SetLongField(jobject obj, jfieldID fieldID, + jlong val) { + functions->SetLongField(this,obj,fieldID,val); + } + void SetFloatField(jobject obj, jfieldID fieldID, + jfloat val) { + functions->SetFloatField(this,obj,fieldID,val); + } + void SetDoubleField(jobject obj, jfieldID fieldID, + jdouble val) { + functions->SetDoubleField(this,obj,fieldID,val); + } + + jmethodID GetStaticMethodID(jclass clazz, const char *name, + const char *sig) { + return functions->GetStaticMethodID(this,clazz,name,sig); + } + + jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, + ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallStaticObjectMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, + va_list args) { + return functions->CallStaticObjectMethodV(this,clazz,methodID,args); + } + jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, + const jvalue *args) { + return functions->CallStaticObjectMethodA(this,clazz,methodID,args); + } + + jboolean CallStaticBooleanMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jboolean CallStaticBooleanMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticBooleanMethodV(this,clazz,methodID,args); + } + jboolean CallStaticBooleanMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticBooleanMethodA(this,clazz,methodID,args); + } + + jbyte CallStaticByteMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallStaticByteMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jbyte CallStaticByteMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticByteMethodV(this,clazz,methodID,args); + } + jbyte CallStaticByteMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticByteMethodA(this,clazz,methodID,args); + } + + jchar CallStaticCharMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallStaticCharMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jchar CallStaticCharMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticCharMethodV(this,clazz,methodID,args); + } + jchar CallStaticCharMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticCharMethodA(this,clazz,methodID,args); + } + + jshort CallStaticShortMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallStaticShortMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jshort CallStaticShortMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticShortMethodV(this,clazz,methodID,args); + } + jshort CallStaticShortMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticShortMethodA(this,clazz,methodID,args); + } + + jint CallStaticIntMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallStaticIntMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jint CallStaticIntMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticIntMethodV(this,clazz,methodID,args); + } + jint CallStaticIntMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticIntMethodA(this,clazz,methodID,args); + } + + jlong CallStaticLongMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallStaticLongMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jlong CallStaticLongMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticLongMethodV(this,clazz,methodID,args); + } + jlong CallStaticLongMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticLongMethodA(this,clazz,methodID,args); + } + + jfloat CallStaticFloatMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallStaticFloatMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jfloat CallStaticFloatMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticFloatMethodV(this,clazz,methodID,args); + } + jfloat CallStaticFloatMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticFloatMethodA(this,clazz,methodID,args); + } + + jdouble CallStaticDoubleMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jdouble CallStaticDoubleMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticDoubleMethodV(this,clazz,methodID,args); + } + jdouble CallStaticDoubleMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticDoubleMethodA(this,clazz,methodID,args); + } + + void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallStaticVoidMethodV(this,cls,methodID,args); + va_end(args); + } + void CallStaticVoidMethodV(jclass cls, jmethodID methodID, + va_list args) { + functions->CallStaticVoidMethodV(this,cls,methodID,args); + } + void CallStaticVoidMethodA(jclass cls, jmethodID methodID, + const jvalue * args) { + functions->CallStaticVoidMethodA(this,cls,methodID,args); + } + + jfieldID GetStaticFieldID(jclass clazz, const char *name, + const char *sig) { + return functions->GetStaticFieldID(this,clazz,name,sig); + } + jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticObjectField(this,clazz,fieldID); + } + jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticBooleanField(this,clazz,fieldID); + } + jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticByteField(this,clazz,fieldID); + } + jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticCharField(this,clazz,fieldID); + } + jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticShortField(this,clazz,fieldID); + } + jint GetStaticIntField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticIntField(this,clazz,fieldID); + } + jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticLongField(this,clazz,fieldID); + } + jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticFloatField(this,clazz,fieldID); + } + jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticDoubleField(this,clazz,fieldID); + } + + void SetStaticObjectField(jclass clazz, jfieldID fieldID, + jobject value) { + functions->SetStaticObjectField(this,clazz,fieldID,value); + } + void SetStaticBooleanField(jclass clazz, jfieldID fieldID, + jboolean value) { + functions->SetStaticBooleanField(this,clazz,fieldID,value); + } + void SetStaticByteField(jclass clazz, jfieldID fieldID, + jbyte value) { + functions->SetStaticByteField(this,clazz,fieldID,value); + } + void SetStaticCharField(jclass clazz, jfieldID fieldID, + jchar value) { + functions->SetStaticCharField(this,clazz,fieldID,value); + } + void SetStaticShortField(jclass clazz, jfieldID fieldID, + jshort value) { + functions->SetStaticShortField(this,clazz,fieldID,value); + } + void SetStaticIntField(jclass clazz, jfieldID fieldID, + jint value) { + functions->SetStaticIntField(this,clazz,fieldID,value); + } + void SetStaticLongField(jclass clazz, jfieldID fieldID, + jlong value) { + functions->SetStaticLongField(this,clazz,fieldID,value); + } + void SetStaticFloatField(jclass clazz, jfieldID fieldID, + jfloat value) { + functions->SetStaticFloatField(this,clazz,fieldID,value); + } + void SetStaticDoubleField(jclass clazz, jfieldID fieldID, + jdouble value) { + functions->SetStaticDoubleField(this,clazz,fieldID,value); + } + + jstring NewString(const jchar *unicode, jsize len) { + return functions->NewString(this,unicode,len); + } + jsize GetStringLength(jstring str) { + return functions->GetStringLength(this,str); + } + const jchar *GetStringChars(jstring str, jboolean *isCopy) { + return functions->GetStringChars(this,str,isCopy); + } + void ReleaseStringChars(jstring str, const jchar *chars) { + functions->ReleaseStringChars(this,str,chars); + } + + jstring NewStringUTF(const char *utf) { + return functions->NewStringUTF(this,utf); + } + jsize GetStringUTFLength(jstring str) { + return functions->GetStringUTFLength(this,str); + } + const char* GetStringUTFChars(jstring str, jboolean *isCopy) { + return functions->GetStringUTFChars(this,str,isCopy); + } + void ReleaseStringUTFChars(jstring str, const char* chars) { + functions->ReleaseStringUTFChars(this,str,chars); + } + + jsize GetArrayLength(jarray array) { + return functions->GetArrayLength(this,array); + } + + jobjectArray NewObjectArray(jsize len, jclass clazz, + jobject init) { + return functions->NewObjectArray(this,len,clazz,init); + } + jobject GetObjectArrayElement(jobjectArray array, jsize index) { + return functions->GetObjectArrayElement(this,array,index); + } + void SetObjectArrayElement(jobjectArray array, jsize index, + jobject val) { + functions->SetObjectArrayElement(this,array,index,val); + } + + jbooleanArray NewBooleanArray(jsize len) { + return functions->NewBooleanArray(this,len); + } + jbyteArray NewByteArray(jsize len) { + return functions->NewByteArray(this,len); + } + jcharArray NewCharArray(jsize len) { + return functions->NewCharArray(this,len); + } + jshortArray NewShortArray(jsize len) { + return functions->NewShortArray(this,len); + } + jintArray NewIntArray(jsize len) { + return functions->NewIntArray(this,len); + } + jlongArray NewLongArray(jsize len) { + return functions->NewLongArray(this,len); + } + jfloatArray NewFloatArray(jsize len) { + return functions->NewFloatArray(this,len); + } + jdoubleArray NewDoubleArray(jsize len) { + return functions->NewDoubleArray(this,len); + } + + jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) { + return functions->GetBooleanArrayElements(this,array,isCopy); + } + jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) { + return functions->GetByteArrayElements(this,array,isCopy); + } + jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) { + return functions->GetCharArrayElements(this,array,isCopy); + } + jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) { + return functions->GetShortArrayElements(this,array,isCopy); + } + jint * GetIntArrayElements(jintArray array, jboolean *isCopy) { + return functions->GetIntArrayElements(this,array,isCopy); + } + jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) { + return functions->GetLongArrayElements(this,array,isCopy); + } + jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) { + return functions->GetFloatArrayElements(this,array,isCopy); + } + jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) { + return functions->GetDoubleArrayElements(this,array,isCopy); + } + + void ReleaseBooleanArrayElements(jbooleanArray array, + jboolean *elems, + jint mode) { + functions->ReleaseBooleanArrayElements(this,array,elems,mode); + } + void ReleaseByteArrayElements(jbyteArray array, + jbyte *elems, + jint mode) { + functions->ReleaseByteArrayElements(this,array,elems,mode); + } + void ReleaseCharArrayElements(jcharArray array, + jchar *elems, + jint mode) { + functions->ReleaseCharArrayElements(this,array,elems,mode); + } + void ReleaseShortArrayElements(jshortArray array, + jshort *elems, + jint mode) { + functions->ReleaseShortArrayElements(this,array,elems,mode); + } + void ReleaseIntArrayElements(jintArray array, + jint *elems, + jint mode) { + functions->ReleaseIntArrayElements(this,array,elems,mode); + } + void ReleaseLongArrayElements(jlongArray array, + jlong *elems, + jint mode) { + functions->ReleaseLongArrayElements(this,array,elems,mode); + } + void ReleaseFloatArrayElements(jfloatArray array, + jfloat *elems, + jint mode) { + functions->ReleaseFloatArrayElements(this,array,elems,mode); + } + void ReleaseDoubleArrayElements(jdoubleArray array, + jdouble *elems, + jint mode) { + functions->ReleaseDoubleArrayElements(this,array,elems,mode); + } + + void GetBooleanArrayRegion(jbooleanArray array, + jsize start, jsize len, jboolean *buf) { + functions->GetBooleanArrayRegion(this,array,start,len,buf); + } + void GetByteArrayRegion(jbyteArray array, + jsize start, jsize len, jbyte *buf) { + functions->GetByteArrayRegion(this,array,start,len,buf); + } + void GetCharArrayRegion(jcharArray array, + jsize start, jsize len, jchar *buf) { + functions->GetCharArrayRegion(this,array,start,len,buf); + } + void GetShortArrayRegion(jshortArray array, + jsize start, jsize len, jshort *buf) { + functions->GetShortArrayRegion(this,array,start,len,buf); + } + void GetIntArrayRegion(jintArray array, + jsize start, jsize len, jint *buf) { + functions->GetIntArrayRegion(this,array,start,len,buf); + } + void GetLongArrayRegion(jlongArray array, + jsize start, jsize len, jlong *buf) { + functions->GetLongArrayRegion(this,array,start,len,buf); + } + void GetFloatArrayRegion(jfloatArray array, + jsize start, jsize len, jfloat *buf) { + functions->GetFloatArrayRegion(this,array,start,len,buf); + } + void GetDoubleArrayRegion(jdoubleArray array, + jsize start, jsize len, jdouble *buf) { + functions->GetDoubleArrayRegion(this,array,start,len,buf); + } + + void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, + const jboolean *buf) { + functions->SetBooleanArrayRegion(this,array,start,len,buf); + } + void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, + const jbyte *buf) { + functions->SetByteArrayRegion(this,array,start,len,buf); + } + void SetCharArrayRegion(jcharArray array, jsize start, jsize len, + const jchar *buf) { + functions->SetCharArrayRegion(this,array,start,len,buf); + } + void SetShortArrayRegion(jshortArray array, jsize start, jsize len, + const jshort *buf) { + functions->SetShortArrayRegion(this,array,start,len,buf); + } + void SetIntArrayRegion(jintArray array, jsize start, jsize len, + const jint *buf) { + functions->SetIntArrayRegion(this,array,start,len,buf); + } + void SetLongArrayRegion(jlongArray array, jsize start, jsize len, + const jlong *buf) { + functions->SetLongArrayRegion(this,array,start,len,buf); + } + void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, + const jfloat *buf) { + functions->SetFloatArrayRegion(this,array,start,len,buf); + } + void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, + const jdouble *buf) { + functions->SetDoubleArrayRegion(this,array,start,len,buf); + } + + jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, + jint nMethods) { + return functions->RegisterNatives(this,clazz,methods,nMethods); + } + jint UnregisterNatives(jclass clazz) { + return functions->UnregisterNatives(this,clazz); + } + + jint MonitorEnter(jobject obj) { + return functions->MonitorEnter(this,obj); + } + jint MonitorExit(jobject obj) { + return functions->MonitorExit(this,obj); + } + + jint GetJavaVM(JavaVM **vm) { + return functions->GetJavaVM(this,vm); + } + + void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) { + functions->GetStringRegion(this,str,start,len,buf); + } + void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) { + functions->GetStringUTFRegion(this,str,start,len,buf); + } + + void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) { + return functions->GetPrimitiveArrayCritical(this,array,isCopy); + } + void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) { + functions->ReleasePrimitiveArrayCritical(this,array,carray,mode); + } + + const jchar * GetStringCritical(jstring string, jboolean *isCopy) { + return functions->GetStringCritical(this,string,isCopy); + } + void ReleaseStringCritical(jstring string, const jchar *cstring) { + functions->ReleaseStringCritical(this,string,cstring); + } + + jweak NewWeakGlobalRef(jobject obj) { + return functions->NewWeakGlobalRef(this,obj); + } + void DeleteWeakGlobalRef(jweak ref) { + functions->DeleteWeakGlobalRef(this,ref); + } + + jboolean ExceptionCheck() { + return functions->ExceptionCheck(this); + } + + jobject NewDirectByteBuffer(void* address, jlong capacity) { + return functions->NewDirectByteBuffer(this, address, capacity); + } + void* GetDirectBufferAddress(jobject buf) { + return functions->GetDirectBufferAddress(this, buf); + } + jlong GetDirectBufferCapacity(jobject buf) { + return functions->GetDirectBufferCapacity(this, buf); + } + jobjectRefType GetObjectRefType(jobject obj) { + return functions->GetObjectRefType(this, obj); + } + +#endif /* __cplusplus */ +}; + +typedef struct JavaVMOption { + char *optionString; + void *extraInfo; +} JavaVMOption; + +typedef struct JavaVMInitArgs { + jint version; + + jint nOptions; + JavaVMOption *options; + jboolean ignoreUnrecognized; +} JavaVMInitArgs; + +typedef struct JavaVMAttachArgs { + jint version; + + char *name; + jobject group; +} JavaVMAttachArgs; + +/* These will be VM-specific. */ + +#define JDK1_2 +#define JDK1_4 + +/* End VM-specific. */ + +struct JNIInvokeInterface_ { + void *reserved0; + void *reserved1; + void *reserved2; + +#if !TARGET_RT_MAC_CFM && defined(__ppc__) + void* cfm_vectors[4]; +#endif /* !TARGET_RT_MAC_CFM && defined(__ppc__) */ + + jint (JNICALL *DestroyJavaVM)(JavaVM *vm); + + jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args); + + jint (JNICALL *DetachCurrentThread)(JavaVM *vm); + + jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version); + + jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args); + +#if TARGET_RT_MAC_CFM && defined(__ppc__) + void* real_functions[5]; +#endif /* TARGET_RT_MAC_CFM && defined(__ppc__) */ +}; + +struct JavaVM_ { + const struct JNIInvokeInterface_ *functions; +#ifdef __cplusplus + + jint DestroyJavaVM() { + return functions->DestroyJavaVM(this); + } + jint AttachCurrentThread(void **penv, void *args) { + return functions->AttachCurrentThread(this, penv, args); + } + jint DetachCurrentThread() { + return functions->DetachCurrentThread(this); + } + + jint GetEnv(void **penv, jint version) { + return functions->GetEnv(this, penv, version); + } + jint AttachCurrentThreadAsDaemon(void **penv, void *args) { + return functions->AttachCurrentThreadAsDaemon(this, penv, args); + } +#endif +}; + +#ifdef _JNI_IMPLEMENTATION_ +#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT +#else +#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT +#endif +_JNI_IMPORT_OR_EXPORT_ __attribute__((deprecated)) jint JNICALL +JNI_GetDefaultJavaVMInitArgs(void *args); + +_JNI_IMPORT_OR_EXPORT_ __attribute__((deprecated)) jint JNICALL +JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); + +_JNI_IMPORT_OR_EXPORT_ __attribute__((deprecated)) jint JNICALL +JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); + +/* Defined by native libraries. */ +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved); + +JNIEXPORT void JNICALL +JNI_OnUnload(JavaVM *vm, void *reserved); + +#define JNI_VERSION_1_1 0x00010001 +#define JNI_VERSION_1_2 0x00010002 +#define JNI_VERSION_1_4 0x00010004 +#define JNI_VERSION_1_6 0x00010006 + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !_JAVASOFT_JNI_H_ */ + + + diff --git a/sqlite3multipleciphers/src/jni/headers/inc_linux/jni_md.h b/sqlite3multipleciphers/src/jni/headers/inc_linux/jni_md.h new file mode 100644 index 00000000..9b5d1a8a --- /dev/null +++ b/sqlite3multipleciphers/src/jni/headers/inc_linux/jni_md.h @@ -0,0 +1,24 @@ +/* + * %W% %E% + * + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#define JNIEXPORT __attribute__((__visibility__("default"))) +#define JNIIMPORT +#define JNICALL + +typedef int jint; +#ifdef _LP64 /* 64-bit Solaris */ +typedef long jlong; +#else +typedef long long jlong; +#endif + +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/sqlite3multipleciphers/src/jni/headers/inc_mac/jni_md.h b/sqlite3multipleciphers/src/jni/headers/inc_mac/jni_md.h new file mode 100644 index 00000000..21cc90b3 --- /dev/null +++ b/sqlite3multipleciphers/src/jni/headers/inc_mac/jni_md.h @@ -0,0 +1,23 @@ +/* + * @(#)jni_md.h 1.19 05/11/17 + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#define JNIEXPORT __attribute__((visibility("default"))) +#define JNIIMPORT +#define JNICALL + +#if defined(__LP64__) && __LP64__ /* for -Wundef */ +typedef int jint; +#else +typedef long jint; +#endif +typedef long long jlong; +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/sqlite3multipleciphers/src/jni/headers/inc_win/jni_md.h b/sqlite3multipleciphers/src/jni/headers/inc_win/jni_md.h new file mode 100644 index 00000000..26a733df --- /dev/null +++ b/sqlite3multipleciphers/src/jni/headers/inc_win/jni_md.h @@ -0,0 +1,19 @@ +/* + * @(#)jni_md.h 1.14 03/12/19 + * + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#define JNIEXPORT __declspec(dllexport) +#define JNIIMPORT __declspec(dllimport) +#define JNICALL __stdcall + +typedef long jint; +typedef __int64 jlong; +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/sqlite3multipleciphers/src/jni/sqlite_bindings.cpp b/sqlite3multipleciphers/src/jni/sqlite_bindings.cpp new file mode 100644 index 00000000..67647da2 --- /dev/null +++ b/sqlite3multipleciphers/src/jni/sqlite_bindings.cpp @@ -0,0 +1,440 @@ +// Upstream source: https://github.com/androidx/androidx/blob/androidx-main/sqlite/sqlite-bundled/src/jvmAndroidMain/jni/sqlite_bindings.cpp + +#include +#include "sqlite3.h" +#include +#include +#include + +/** + * Throws SQLiteException with the given error code and message. + * + * @return true if the exception was thrown, otherwise false. + */ +static bool throwSQLiteException(JNIEnv *env, int errorCode, const char *errorMsg) { + jclass exceptionClass = env->FindClass("androidx/sqlite/SQLiteException"); + if (exceptionClass == nullptr) { + // If androidx's exception isn't found we are likely in Android's native where the + // actual exception is type aliased. Clear the ClassNotFoundException and instead find + // and throw Android's exception. + env->ExceptionClear(); + exceptionClass = env->FindClass("android/database/SQLException"); + } + int codeLength = snprintf(nullptr, 0, "%d", errorCode); + size_t prefixLength = strlen("Error code: "); + size_t msgLength = 0; + if (errorMsg != nullptr) { + msgLength = strlen(", message: ") + strlen(errorMsg); + } + size_t totalSize = prefixLength + codeLength + msgLength + 1; + char* message = (char*) malloc(totalSize); + if (errorMsg != nullptr) { + snprintf(message, totalSize, "Error code: %d, message: %s", errorCode, errorMsg); + } else { + snprintf(message, totalSize, "Error code: %d", errorCode); + } + int throwResult = env->ThrowNew(exceptionClass, message); + free(message); + return throwResult == 0; +} + +static bool throwIfNoRow(JNIEnv *env, sqlite3_stmt *stmt) { + if (sqlite3_stmt_busy(stmt) == 0) { + return throwSQLiteException(env, SQLITE_MISUSE, "no row"); + } + return false; +} + +static bool throwIfInvalidColumn(JNIEnv *env, sqlite3_stmt *stmt, int index) { + if (index < 0 || index >= sqlite3_column_count(stmt)) { + return throwSQLiteException(env, SQLITE_RANGE, "column index out of range"); + } + return false; +} + +static bool throwOutOfMemoryError(JNIEnv *env) { + jclass exceptionClass = env->FindClass("java/lang/OutOfMemoryError"); + int throwResult = env->ThrowNew(exceptionClass, nullptr); + return throwResult == 0; +} + +static bool throwIfOutOfMemory(JNIEnv *env, sqlite3_stmt *stmt) { + int lastRc = sqlite3_errcode(sqlite3_db_handle(stmt)); + if (lastRc == SQLITE_NOMEM) { + return throwOutOfMemoryError(env); + } + return false; +} + +static jlong JNICALL nativeOpen( + JNIEnv *env, + jclass clazz, + jstring name, + int openFlags) { + const char *path = env->GetStringUTFChars(name, nullptr); + sqlite3 *db; + int rc = sqlite3_open_v2(path, &db, openFlags, nullptr); + env->ReleaseStringUTFChars(name, path); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, nullptr); + return 0; + } + + // Enable extended error codes + rc = sqlite3_extended_result_codes(db, 1); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, nullptr); + return 0; + } + + // Enable the C function to load extensions but not the load_extension() SQL function. + rc = sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, nullptr); + return 0; + } + + return reinterpret_cast(db); +} + +static jboolean JNICALL nativeInTransaction( + JNIEnv *env, + jclass clazz, + jlong dbPointer) { + sqlite3 *db = reinterpret_cast(dbPointer); + if (sqlite3_get_autocommit(db) == 0) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } +} + +static jlong JNICALL nativePrepare( + JNIEnv *env, + jclass clazz, + jlong dbPointer, + jstring sqlString) { + sqlite3 *db = reinterpret_cast(dbPointer); + sqlite3_stmt *stmt; + jsize sqlLength = env->GetStringLength(sqlString); + // Java / jstring represents a string in UTF-16 encoding. + const jchar *sql = env->GetStringCritical(sqlString, nullptr); + int rc = sqlite3_prepare16_v2(db, sql, sqlLength * sizeof(jchar), &stmt, nullptr); + env->ReleaseStringCritical(sqlString, sql); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, sqlite3_errmsg(db)); + return 0; + } + return reinterpret_cast(stmt); +} + +static void JNICALL nativeLoadExtension( + JNIEnv *env, + jclass clazz, + jlong dbPointer, + jstring fileName, + jstring entryPoint) { + sqlite3 *db = reinterpret_cast(dbPointer); + const char *zFileName = env->GetStringUTFChars(fileName, nullptr); + const char *zEntryPoint = nullptr; + if (entryPoint) { + zEntryPoint = env->GetStringUTFChars(entryPoint, nullptr); + } + char *errorMsg = nullptr; + int rc = sqlite3_load_extension(db, zFileName, zEntryPoint, &errorMsg); + env->ReleaseStringUTFChars(fileName, zFileName); + if (entryPoint) { + env->ReleaseStringUTFChars(entryPoint, zEntryPoint); + } + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, errorMsg); + if (errorMsg) { + sqlite3_free(errorMsg); + } + } +} + +static void JNICALL nativeConnectionClose( + JNIEnv *env, + jclass clazz, + jlong dbPointer) { + sqlite3 *db = reinterpret_cast(dbPointer); + sqlite3_close_v2(db); +} + +static void JNICALL nativeBindBlob( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index, + jbyteArray value) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + jsize valueLength = env->GetArrayLength(value); + jbyte *blob = static_cast(env->GetPrimitiveArrayCritical(value, nullptr)); + int rc = sqlite3_bind_blob(stmt, index, blob, valueLength, SQLITE_TRANSIENT); + env->ReleasePrimitiveArrayCritical(value, blob, JNI_ABORT); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, sqlite3_errmsg(sqlite3_db_handle(stmt))); + } +} + +static void JNICALL nativeBindDouble( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index, + jdouble value) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + int rc = sqlite3_bind_double(stmt, index, value); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, sqlite3_errmsg(sqlite3_db_handle(stmt))); + } +} + +static void JNICALL nativeBindLong( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index, + jlong value) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + int rc = sqlite3_bind_int64(stmt, index, value); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, sqlite3_errmsg(sqlite3_db_handle(stmt))); + } +} + +static void JNICALL nativeBindText( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index, + jstring value) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + jsize valueLength = env->GetStringLength(value); + const jchar *text = env->GetStringCritical(value, NULL); + int rc = sqlite3_bind_text16(stmt, index, text, valueLength * sizeof(jchar), SQLITE_TRANSIENT); + env->ReleaseStringCritical(value, text); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, sqlite3_errmsg(sqlite3_db_handle(stmt))); + } +} + +static void JNICALL nativeBindNull( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + int rc = sqlite3_bind_null(stmt, index); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, sqlite3_errmsg(sqlite3_db_handle(stmt))); + } +} + +static jboolean JNICALL nativeStep( + JNIEnv *env, + jclass clazz, + jlong stmtPointer) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + int rc = sqlite3_step(stmt); + if (rc == SQLITE_ROW) { + return JNI_TRUE; + } + if (rc == SQLITE_DONE) { + return JNI_FALSE; + } + throwSQLiteException(env, rc, sqlite3_errmsg(sqlite3_db_handle(stmt))); + return JNI_FALSE; +} + +static jbyteArray JNICALL nativeGetBlob( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + if (throwIfNoRow(env, stmt)) return nullptr; + if (throwIfInvalidColumn(env, stmt, index)) return nullptr; + const void *blob = sqlite3_column_blob(stmt, index); + if (blob == nullptr && throwIfOutOfMemory(env, stmt)) return nullptr; + int size = sqlite3_column_bytes(stmt, index); + if (size == 0 && throwIfOutOfMemory(env, stmt)) return nullptr; + jbyteArray byteArray = env->NewByteArray(size); + if (size > 0) { + env->SetByteArrayRegion(byteArray, 0, size, static_cast(blob)); + } + return byteArray; +} + +static jdouble JNICALL nativeGetDouble( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + if (throwIfNoRow(env, stmt)) return 0.0; + if (throwIfInvalidColumn(env, stmt, index)) return 0.0; + return sqlite3_column_double(stmt, index); +} + +static jlong JNICALL nativeGetLong( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + if (throwIfNoRow(env, stmt)) return 0; + if (throwIfInvalidColumn(env, stmt, index)) return 0; + return sqlite3_column_int64(stmt, index); +} + +static jstring JNICALL nativeGetText( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + if (throwIfNoRow(env, stmt)) return nullptr; + if (throwIfInvalidColumn(env, stmt, index)) return nullptr; + // Java / jstring represents a string in UTF-16 encoding. + const jchar *text = static_cast(sqlite3_column_text16(stmt, index)); + if (text == nullptr && throwIfOutOfMemory(env, stmt)) return nullptr; + size_t length = sqlite3_column_bytes16(stmt, index) / sizeof(jchar); + if (length == 0 && throwIfOutOfMemory(env, stmt)) return nullptr; + return env->NewString(text, length); +} + +static jint JNICALL nativeGetColumnCount( + JNIEnv *env, + jclass clazz, + jlong stmtPointer) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + return sqlite3_column_count(stmt); +} + +static jstring JNICALL nativeGetColumnName( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + if (throwIfInvalidColumn(env, stmt, index)) return nullptr; + const char *name = sqlite3_column_name(stmt, index); + if (name == nullptr) { + throwOutOfMemoryError(env); + return nullptr; + } + return env->NewStringUTF(name); +} + +static jint JNICALL nativeGetColumnType( + JNIEnv *env, + jclass clazz, + jlong stmtPointer, + jint index) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + if (throwIfNoRow(env, stmt)) return 0; + if (throwIfInvalidColumn(env, stmt, index)) return 0; + return sqlite3_column_type(stmt, index); +} + +static void JNICALL nativeReset( + JNIEnv *env, + jclass clazz, + jlong stmtPointer) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + int rc = sqlite3_reset(stmt); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, sqlite3_errmsg(sqlite3_db_handle(stmt))); + } +} + +static void JNICALL nativeClearBindings( + JNIEnv *env, + jclass clazz, + jlong stmtPointer) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + int rc = sqlite3_clear_bindings(stmt); + if (rc != SQLITE_OK) { + throwSQLiteException(env, rc, sqlite3_errmsg(sqlite3_db_handle(stmt))); + } +} + +static void JNICALL nativeStatementClose( + JNIEnv *env, + jclass clazz, + jlong stmtPointer) { + sqlite3_stmt *stmt = reinterpret_cast(stmtPointer); + sqlite3_finalize(stmt); +} + +static const JNINativeMethod sDriverMethods[] = { + {"nativeOpen", "(Ljava/lang/String;I)J", (void *) nativeOpen} +}; + +static const JNINativeMethod sConnectionMethods[] = { + {"nativeInTransaction", "(J)Z", (void *) nativeInTransaction}, + {"nativePrepare", "(JLjava/lang/String;)J", (void *) nativePrepare}, + {"nativeLoadExtension", "(JLjava/lang/String;Ljava/lang/String;)V", (void *) nativeLoadExtension}, + {"nativeClose", "(J)V", (void *) nativeConnectionClose} +}; + +static const JNINativeMethod sStatementMethods[] = { + {"nativeBindBlob", "(JI[B)V", (void *) nativeBindBlob}, + {"nativeBindDouble", "(JID)V", (void *) nativeBindDouble}, + {"nativeBindLong", "(JIJ)V", (void *) nativeBindLong}, + {"nativeBindText", "(JILjava/lang/String;)V", (void *) nativeBindText}, + {"nativeBindNull", "(JI)V", (void *) nativeBindNull}, + {"nativeStep", "(J)Z", (void *) nativeStep}, + {"nativeGetBlob", "(JI)[B", (void *) nativeGetBlob}, + {"nativeGetDouble", "(JI)D", (void *) nativeGetDouble}, + {"nativeGetLong", "(JI)J", (void *) nativeGetLong}, + {"nativeGetText", "(JI)Ljava/lang/String;", (void *) nativeGetText}, + {"nativeGetColumnCount", "(J)I", (void *) nativeGetColumnCount}, + {"nativeGetColumnName", "(JI)Ljava/lang/String;", (void *) nativeGetColumnName}, + {"nativeGetColumnType", "(JI)I", (void *) nativeGetColumnType}, + {"nativeReset", "(J)V", (void *) nativeReset}, + {"nativeClearBindings", "(J)V", (void *) nativeClearBindings}, + {"nativeClose", "(J)V", (void *) nativeStatementClose}, +}; + +static int register_methods(JNIEnv *env, const char *className, + const JNINativeMethod *methods, + int methodCount) { + jclass clazz = env->FindClass(className); + if (clazz == nullptr) { + return JNI_ERR; + } + int result = env->RegisterNatives(clazz, methods, methodCount); + env->DeleteLocalRef(clazz); + if (result != 0) { + return JNI_ERR; + } + return JNI_OK; +} + +jint JNI_OnLoad(JavaVM *vm, void * /* reserved */) { + JNIEnv *env = nullptr; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6)) { + return JNI_ERR; + } + + const int driverMethodCount = sizeof(sDriverMethods) / sizeof(sDriverMethods[0]); + if (register_methods(env, "com/powersync/encryption/BundledSQLiteDriverKt", + sDriverMethods, driverMethodCount) != JNI_OK) { + return JNI_ERR; + } + const int connectionMethodCount = sizeof(sConnectionMethods) / sizeof(sConnectionMethods[0]); + if (register_methods(env, "com/powersync/encryption/BundledSQLiteConnectionKt", + sConnectionMethods, connectionMethodCount) != JNI_OK) { + return JNI_ERR; + } + const int statementMethodCount = sizeof(sStatementMethods) / sizeof(sStatementMethods[0]); + if (register_methods(env, "com/powersync/encryption/BundledSQLiteStatementKt", + sStatementMethods, statementMethodCount) != JNI_OK) { + return JNI_ERR; + } + + return JNI_VERSION_1_6; +} diff --git a/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteConnection.kt b/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteConnection.kt new file mode 100644 index 00000000..a3ec47c5 --- /dev/null +++ b/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteConnection.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * 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. + */ +@file:JvmName("BundledSQLiteConnectionKt") +package com.powersync.encryption + +import androidx.sqlite.SQLiteConnection +import androidx.sqlite.SQLiteStatement +import androidx.sqlite.throwSQLiteException + +internal class BundledSQLiteConnection(private val connectionPointer: Long) : SQLiteConnection { + @Volatile private var isClosed = false + + override fun inTransaction(): Boolean { + if (isClosed) { + throwSQLiteException(SQLITE_MISUSE, "connection is closed") + } + return nativeInTransaction(connectionPointer) + } + + override fun prepare(sql: String): SQLiteStatement { + if (isClosed) { + throwSQLiteException(SQLITE_MISUSE, "connection is closed") + } + val statementPointer = nativePrepare(connectionPointer, sql) + return BundledSQLiteStatement(connectionPointer, statementPointer) + } + + internal fun loadExtension(fileName: String, entryPoint: String?) { + if (isClosed) { + throwSQLiteException(SQLITE_MISUSE, "connection is closed") + } + + nativeLoadExtension(connectionPointer, fileName, entryPoint) + } + + override fun close() { + if (!isClosed) { + isClosed = true + nativeClose(connectionPointer) + } + } + + private companion object { + private const val SQLITE_MISUSE = 21 + } +} + +private external fun nativeInTransaction(pointer: Long): Boolean + +private external fun nativePrepare(pointer: Long, sql: String): Long + +private external fun nativeLoadExtension(pointer: Long, fileName: String, entryPoint: String?) + +private external fun nativeClose(pointer: Long) diff --git a/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.kt b/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.kt new file mode 100644 index 00000000..321451e8 --- /dev/null +++ b/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * 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. + */ +@file:JvmName("BundledSQLiteDriverKt") +package com.powersync.encryption + +import androidx.sqlite.SQLiteConnection +import com.powersync.PersistentConnectionFactory +import com.powersync.resolvePowerSyncLoadableExtensionPath + +public abstract class BundledSQLiteDriver internal constructor(private val key: Key): PersistentConnectionFactory { + private fun open(fileName: String, flags: Int): SQLiteConnection { + ensureJniLibraryLoaded() + + val address = nativeOpen(fileName, flags) + val connection = BundledSQLiteConnection(address) + try { + connection.loadExtension(resolvePowerSyncLoadableExtensionPath()!!, "sqlite3_powersync_init") + } catch (th: Throwable) { + connection.close() + throw th + } + + return connection + } + + override fun openConnection(path: String, openFlags: Int): SQLiteConnection { + return open(path, openFlags).also { it.encryptOrClose(key) } + } + + override fun openInMemoryConnection(): SQLiteConnection { + return open(":memory:", 2) + } +} + +internal expect fun ensureJniLibraryLoaded() + +private external fun nativeOpen(name: String, openFlags: Int): Long diff --git a/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteStatement.kt b/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteStatement.kt new file mode 100644 index 00000000..d700057b --- /dev/null +++ b/sqlite3multipleciphers/src/jvmAndroidMain/kotlin/com/powersync/encryption/BundledSQLiteStatement.kt @@ -0,0 +1,147 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * 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. + */ +@file:JvmName("BundledSQLiteStatementKt") +package com.powersync.encryption + +import androidx.sqlite.SQLiteStatement +import androidx.sqlite.throwSQLiteException + +internal class BundledSQLiteStatement( + private val connectionPointer: Long, + private val statementPointer: Long, +) : SQLiteStatement { + + @Volatile private var isClosed = false + + override fun bindBlob(index: Int, value: ByteArray) { + throwIfClosed() + nativeBindBlob(statementPointer, index, value) + } + + override fun bindDouble(index: Int, value: Double) { + throwIfClosed() + nativeBindDouble(statementPointer, index, value) + } + + override fun bindLong(index: Int, value: Long) { + throwIfClosed() + nativeBindLong(statementPointer, index, value) + } + + override fun bindText(index: Int, value: String) { + throwIfClosed() + nativeBindText(statementPointer, index, value) + } + + override fun bindNull(index: Int) { + throwIfClosed() + nativeBindNull(statementPointer, index) + } + + override fun getBlob(index: Int): ByteArray { + throwIfClosed() + return nativeGetBlob(statementPointer, index) + } + + override fun getDouble(index: Int): Double { + throwIfClosed() + return nativeGetDouble(statementPointer, index) + } + + override fun getLong(index: Int): Long { + throwIfClosed() + return nativeGetLong(statementPointer, index) + } + + override fun getText(index: Int): String { + throwIfClosed() + return nativeGetText(statementPointer, index) + } + + override fun isNull(index: Int): Boolean { + throwIfClosed() + return nativeGetColumnType(statementPointer, index) == COLUMN_TYPE_NULL + } + + override fun getColumnCount(): Int { + throwIfClosed() + return nativeGetColumnCount(statementPointer) + } + + override fun getColumnName(index: Int): String { + throwIfClosed() + return nativeGetColumnName(statementPointer, index) + } + + override fun getColumnType(index: Int): Int { + throwIfClosed() + return nativeGetColumnType(statementPointer, index) + } + + override fun step(): Boolean { + throwIfClosed() + return nativeStep(statementPointer) + } + + override fun reset() { + throwIfClosed() + nativeReset(statementPointer) + } + + override fun clearBindings() { + throwIfClosed() + nativeClearBindings(statementPointer) + } + + override fun close() { + if (!isClosed) { + isClosed = true + nativeClose(statementPointer) + } + } + + private fun throwIfClosed() { + if (isClosed) { + throwSQLiteException(21 /* SQLITE_MISUSE */, "statement is closed") + } + } + + private companion object { + private const val COLUMN_TYPE_NULL = 5 + } +} + + +private external fun nativeBindBlob(pointer: Long, index: Int, value: ByteArray) +private external fun nativeBindDouble(pointer: Long, index: Int, value: Double) +private external fun nativeBindLong(pointer: Long, index: Int, value: Long) +private external fun nativeBindText(pointer: Long, index: Int, value: String) +private external fun nativeBindNull(pointer: Long, index: Int) + +private external fun nativeStep(pointer: Long): Boolean + +private external fun nativeGetBlob(pointer: Long, index: Int): ByteArray +private external fun nativeGetDouble(pointer: Long, index: Int): Double +private external fun nativeGetLong(pointer: Long, index: Int): Long +private external fun nativeGetText(pointer: Long, index: Int): String +private external fun nativeGetColumnCount(pointer: Long): Int +private external fun nativeGetColumnName(pointer: Long, index: Int): String +private external fun nativeGetColumnType(pointer: Long, index: Int): Int + +private external fun nativeReset(pointer: Long) + +private external fun nativeClearBindings(pointer: Long) +private external fun nativeClose(pointer: Long) diff --git a/sqlite3multipleciphers/src/jvmMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.jvm.kt b/sqlite3multipleciphers/src/jvmMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.jvm.kt new file mode 100644 index 00000000..03dae4ef --- /dev/null +++ b/sqlite3multipleciphers/src/jvmMain/kotlin/com/powersync/encryption/BundledSQLiteDriver.jvm.kt @@ -0,0 +1,18 @@ +package com.powersync.encryption + +import com.powersync.extractLib + +public class JavaEncryptedDatabaseFactory(key: Key): BundledSQLiteDriver(key) { + override fun resolveDefaultDatabasePath(dbFilename: String): String { + return dbFilename + } +} + +private val didLoadLibrary by lazy { + val path = extractLib(JavaEncryptedDatabaseFactory::class, "sqlite3mc_jni") + System.load(path) +} + +internal actual fun ensureJniLibraryLoaded() { + didLoadLibrary +} diff --git a/sqlite3multipleciphers/src/jvmTest/kotlin/com/powersync/JvmSmokeTest.kt b/sqlite3multipleciphers/src/jvmTest/kotlin/com/powersync/JvmSmokeTest.kt new file mode 100644 index 00000000..9846cc5f --- /dev/null +++ b/sqlite3multipleciphers/src/jvmTest/kotlin/com/powersync/JvmSmokeTest.kt @@ -0,0 +1,23 @@ +package com.powersync + +import com.powersync.encryption.JavaEncryptedDatabaseFactory +import com.powersync.encryption.Key +import io.kotest.matchers.shouldBe +import kotlin.test.Test +import kotlin.use + +class JvmSmokeTest { + @Test + fun linksSqlite3MultipleCiphers() { + JavaEncryptedDatabaseFactory(key).openInMemoryConnection().use { db -> + db.prepare("PRAGMA cipher").use { stmt -> + stmt.step() shouldBe true + stmt.getText(0) shouldBe "chacha20" + } + } + } + + private companion object Companion { + val key = Key.Passphrase("test") + } +} diff --git a/sqlite3multipleciphers/src/nativeMain/kotlin/com/powersync/encryption/EncryptedDatabaseFactory.kt b/sqlite3multipleciphers/src/nativeMain/kotlin/com/powersync/encryption/EncryptedDatabaseFactory.kt new file mode 100644 index 00000000..5b6b8933 --- /dev/null +++ b/sqlite3multipleciphers/src/nativeMain/kotlin/com/powersync/encryption/EncryptedDatabaseFactory.kt @@ -0,0 +1,23 @@ +package com.powersync.encryption + +import androidx.sqlite.SQLiteConnection +import com.powersync.appleDefaultDatabasePath +import com.powersync.db.NativeConnectionFactory + +/** + * A [NativeConnectionFactory] that links sqlite3multipleciphers and opens database with a [Key]. + */ +public class NativeEncryptedDatabaseFactory(private val key: Key): NativeConnectionFactory() { + override fun resolveDefaultDatabasePath(dbFilename: String): String { + return appleDefaultDatabasePath(dbFilename) + } + + override fun openConnection(path: String, openFlags: Int): SQLiteConnection { + return super.openConnection(path, openFlags).apply { + if (path != ":memory:") { + // Settings keys for in-memory or temporary databases is not supported. + encryptOrClose(key) + } + } + } +} diff --git a/sqlite3multipleciphers/src/nativeTest/kotlin/com/powersync/NativeSmokeTest.kt b/sqlite3multipleciphers/src/nativeTest/kotlin/com/powersync/NativeSmokeTest.kt new file mode 100644 index 00000000..ff662161 --- /dev/null +++ b/sqlite3multipleciphers/src/nativeTest/kotlin/com/powersync/NativeSmokeTest.kt @@ -0,0 +1,22 @@ +package com.powersync + +import com.powersync.encryption.Key +import com.powersync.encryption.NativeEncryptedDatabaseFactory +import io.kotest.matchers.shouldBe +import kotlin.test.Test + +class NativeSmokeTest { + @Test + fun linksSqlite3MultipleCiphers() { + NativeEncryptedDatabaseFactory(key).openInMemoryConnection().use { db -> + db.prepare("PRAGMA cipher").use { stmt -> + stmt.step() shouldBe true + stmt.getText(0) shouldBe "chacha20" + } + } + } + + private companion object Companion { + val key = Key.Passphrase("test") + } +} diff --git a/static-sqlite-driver/build.gradle.kts b/static-sqlite-driver/build.gradle.kts index f6c2cbc1..35556063 100644 --- a/static-sqlite-driver/build.gradle.kts +++ b/static-sqlite-driver/build.gradle.kts @@ -74,7 +74,7 @@ fun compileSqlite(target: KotlinNativeTarget): TaskProvider