diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/Definitions.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/Definitions.kt index 8bd8253..a361163 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/Definitions.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/Definitions.kt @@ -1,5 +1,6 @@ package com.ionspin.kotlin.crypto.generator.libsodium.definitions +import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.asTypeName @@ -46,7 +47,7 @@ class FunctionDefinition( val jsName: String, val nativeName: String, val parameterList: MutableList = mutableListOf(), - val returnType: TypeDefinition + val returnType: GeneralTypeDefinition ) { operator fun ParameterDefinition.unaryPlus() { parameterList.add(this) @@ -55,11 +56,19 @@ class FunctionDefinition( class ParameterDefinition( val parameterName: String, - val parameterType: TypeDefinition + val parameterType: GeneralTypeDefinition, + val modifiesReturn: Boolean = false ) -enum class TypeDefinition(val typeName: TypeName) { +interface GeneralTypeDefinition { + val typeName : TypeName +} + +data class CustomTypeDefinition(override val typeName: TypeName) : GeneralTypeDefinition + +enum class TypeDefinition(override val typeName: TypeName) : GeneralTypeDefinition { ARRAY_OF_UBYTES(UByteArray::class.asTypeName()), + ARRAY_OF_UBYTES_NO_SIZE(UByteArray::class.asTypeName()), LONG(Long::class.asTypeName()), INT(Int::class.asTypeName()), STRING(String::class.asTypeName()) @@ -100,7 +109,8 @@ fun funcDef( javaName: String, jsName: String, nativeName: String, - returnType: TypeDefinition, body: FunctionDefinition.() -> Unit + returnType: GeneralTypeDefinition, + body: FunctionDefinition.() -> Unit ): FunctionDefinition { val function = FunctionDefinition(name, javaName, jsName, nativeName, returnType = returnType) function.body() @@ -109,20 +119,37 @@ fun funcDef( object LibSodiumDefinitions { - val testKotlinFile = fileDef("Test.kt") { + val testKotlinFile = fileDef("DebugTest") { +classDef("Hashing") { +innerClassDef( "Sha256State", - "Hash.State256", + "com.goterl.lazycode.lazysodium.interfaces.Hash.State256", "Sha256State", "crypto_hash_sha256_state" ) +funcDef( - "test", "test", "test", "test", TypeDefinition.ARRAY_OF_UBYTES + "init", + "crypto_hash_sha256_init", + "crypto_hash_sha256_init", + "crypto_hash_sha256_init", + TypeDefinition.INT ) { - +ParameterDefinition("first", TypeDefinition.ARRAY_OF_UBYTES) - +ParameterDefinition("second", TypeDefinition.LONG) - +ParameterDefinition("third", TypeDefinition.STRING) + +ParameterDefinition("state", CustomTypeDefinition(ClassName.bestGuess("Sha256State"))) + } + } + + +classDef("GenericHash") { + + +funcDef( + "init", + "crypto_generichash_init", + "crypto_generichash_init", + "crypto_generichash_init", + TypeDefinition.INT + ) { + +ParameterDefinition("state", TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE) + +ParameterDefinition("key", TypeDefinition.ARRAY_OF_UBYTES) + +ParameterDefinition("outlen", TypeDefinition.INT, modifiesReturn = true) } } } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt index df7e041..e2a17a7 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt @@ -1,7 +1,7 @@ package com.ionspin.kotlin.crypto.generator.libsodium.generator -import com.ionspin.kotlin.crypto.generator.libsodium.definitions.ClassDefinition import com.ionspin.kotlin.crypto.generator.libsodium.definitions.FunctionDefinition +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.InnerClassDefinition import com.ionspin.kotlin.crypto.generator.libsodium.definitions.KotlinFileDefinition import com.squareup.kotlinpoet.* @@ -11,7 +11,7 @@ import com.squareup.kotlinpoet.* * on 31-Jul-2020 */ -enum class MultiplatformModifier(val modifierList : List) { +enum class MultiplatformModifier(val modifierList: List) { EXPECT(listOf(KModifier.EXPECT)), ACTUAL(listOf(KModifier.ACTUAL)), NONE(listOf()) @@ -22,8 +22,16 @@ object CommonLibsodiumGenerator { fun createCommonFile(packageName: String, fileDefinition: KotlinFileDefinition): FileSpec { val fileBuilder = FileSpec.builder(packageName, fileDefinition.name) for (commonClassDefinition in fileDefinition.commonClassList) { + //Create expected inner classes that will be represented by type-aliases + commonClassDefinition.innerClasses.forEach { + fileBuilder.addType(createCommonInnerClassSpec(it, MultiplatformModifier.EXPECT)) + } val commonClassSpec = - createClass(commonClassDefinition, MultiplatformModifier.EXPECT, ::createCommonMethodSpec) + createClass( + commonClassDefinition, + MultiplatformModifier.EXPECT, + ::createCommonMethodSpec + ) fileBuilder.addType(commonClassSpec) } val file = fileBuilder.build() @@ -31,6 +39,16 @@ object CommonLibsodiumGenerator { return file } + fun createCommonInnerClassSpec( + innerClassDefinition: InnerClassDefinition, + multiplatformModifier: MultiplatformModifier + ): TypeSpec { + val innerClassBuilder = TypeSpec.classBuilder(innerClassDefinition.name) + innerClassBuilder.modifiers += multiplatformModifier.modifierList + + return innerClassBuilder.build() + } + fun createCommonMethodSpec(methodDefinition: FunctionDefinition): FunSpec { val methodBuilder = FunSpec.builder(methodDefinition.name) for (paramDefinition in methodDefinition.parameterList) { diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/Coordinator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/Coordinator.kt index 48d52e4..c054e1b 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/Coordinator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/Coordinator.kt @@ -1,6 +1,7 @@ package com.ionspin.kotlin.crypto.generator.libsodium.generator import com.ionspin.kotlin.crypto.generator.libsodium.definitions.LibSodiumDefinitions +import java.io.File /** * Created by Ugljesa Jovanovic @@ -10,7 +11,11 @@ import com.ionspin.kotlin.crypto.generator.libsodium.definitions.LibSodiumDefini object Coordinator { fun run(packageName: String) { - CommonLibsodiumGenerator.createCommonFile(packageName, LibSodiumDefinitions.testKotlinFile) - JvmLibsodiumGenerator.createJvmFile(packageName, LibSodiumDefinitions.testKotlinFile) + val commonFileSpec = CommonLibsodiumGenerator.createCommonFile(packageName, LibSodiumDefinitions.testKotlinFile) + val jvmFileSpec = JvmLibsodiumGenerator.createJvmFile(packageName, LibSodiumDefinitions.testKotlinFile) + val commonFile = File("multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/") + commonFileSpec.writeTo(commonFile) + val jvmFile = File("multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/") + jvmFileSpec.writeTo(jvmFile) } } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt index 2b59aaf..08f6c05 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt @@ -1,10 +1,7 @@ package com.ionspin.kotlin.crypto.generator.libsodium.generator -import com.ionspin.kotlin.crypto.generator.libsodium.definitions.FunctionDefinition -import com.ionspin.kotlin.crypto.generator.libsodium.definitions.KotlinFileDefinition -import com.squareup.kotlinpoet.FileSpec -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.ParameterSpec +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.* +import com.squareup.kotlinpoet.* /** * Created by Ugljesa Jovanovic @@ -14,10 +11,22 @@ import com.squareup.kotlinpoet.ParameterSpec object JvmLibsodiumGenerator { - fun createJvmFile(packageName: String, fileDefinition: KotlinFileDefinition) : FileSpec { + fun createJvmFile(packageName: String, fileDefinition: KotlinFileDefinition): FileSpec { val fileBuilder = FileSpec.builder(packageName, fileDefinition.name) + val sodiumProperty = PropertySpec.builder("sodium", ClassName.bestGuess("com.goterl.lazycode.lazysodium.SodiumJava")) + sodiumProperty.initializer(CodeBlock.of("SodiumJava()")) + fileBuilder.addProperty(sodiumProperty.build()) for (commonClassDefinition in fileDefinition.commonClassList) { - val commonClassSpec = createClass(commonClassDefinition, MultiplatformModifier.ACTUAL, ::createJvmFunctionImplementation) + //Create type-aliases + commonClassDefinition.innerClasses.forEach { + fileBuilder.addTypeAlias(createJvmInnerClassSpec(it, MultiplatformModifier.ACTUAL)) + } + + val commonClassSpec = createClass( + commonClassDefinition, + MultiplatformModifier.ACTUAL, + ::createJvmFunctionImplementation + ) fileBuilder.addType(commonClassSpec) } val file = fileBuilder.build() @@ -25,17 +34,101 @@ object JvmLibsodiumGenerator { return file } - fun createJvmFunctionImplementation(methodDefinition: FunctionDefinition) : FunSpec { + fun createJvmInnerClassSpec( + innerClassDefinition: InnerClassDefinition, + multiplatformModifier: MultiplatformModifier + ): TypeAliasSpec { + val innerClassBuilder = TypeAliasSpec.builder(innerClassDefinition.name, ClassName.bestGuess(innerClassDefinition.javaName)) + innerClassBuilder.modifiers += multiplatformModifier.modifierList + + return innerClassBuilder.build() + } + + fun createJvmFunctionImplementation(methodDefinition: FunctionDefinition): FunSpec { val methodBuilder = FunSpec.builder(methodDefinition.name) + methodBuilder.modifiers += MultiplatformModifier.ACTUAL.modifierList + var returnModifierFound = false + var returnModifierName = "" for (paramDefinition in methodDefinition.parameterList) { val parameterSpec = ParameterSpec.builder(paramDefinition.parameterName, paramDefinition.parameterType.typeName) methodBuilder.addParameter(parameterSpec.build()) + if (paramDefinition.modifiesReturn) { + if (returnModifierFound == true) { + throw RuntimeException("Return modifier already found") + } + returnModifierFound = true + returnModifierName = paramDefinition.parameterName + } } - methodBuilder.addStatement("val test1 = ${methodDefinition.javaName}") + if (methodDefinition.returnType == TypeDefinition.ARRAY_OF_UBYTES) { + methodBuilder.addStatement("println(\"Debug\")") + val constructJvmCall = StringBuilder() + constructJvmCall.append("return sodium.${methodDefinition.javaName}") + constructJvmCall.append(paramsToString(methodDefinition)) + + methodBuilder.addStatement(constructJvmCall.toString()) + } + + if (methodDefinition.returnType == TypeDefinition.INT) { + methodBuilder.addStatement("println(\"Debug\")") + val constructJvmCall = StringBuilder() + constructJvmCall.append("return sodium.${methodDefinition.javaName}") + constructJvmCall.append(paramsToString(methodDefinition)) + + methodBuilder.addStatement(constructJvmCall.toString()) + } + + if (methodDefinition.returnType is CustomTypeDefinition) { + methodBuilder.addStatement("println(\"Debug\")") + val constructJvmCall = StringBuilder() + constructJvmCall.append("return sodium.${methodDefinition.javaName}") + constructJvmCall.append(paramsToString(methodDefinition)) + + methodBuilder.addStatement(constructJvmCall.toString()) + } + methodBuilder.returns(methodDefinition.returnType.typeName) return methodBuilder.build() } + fun paramsToString(methodDefinition: FunctionDefinition) : String { + val paramsBuilder = StringBuilder() + paramsBuilder.append("(") + methodDefinition.parameterList.forEachIndexed { index, paramDefinition -> + val separator = if (index == methodDefinition.parameterList.size - 1) { + "" + } else { + ", " + } + if (paramDefinition.parameterType is CustomTypeDefinition) { + paramsBuilder.append(paramDefinition.parameterName + separator) + } + if (paramDefinition.parameterType is TypeDefinition) { + when(paramDefinition.parameterType) { + TypeDefinition.ARRAY_OF_UBYTES -> { + paramsBuilder.append(paramDefinition.parameterName + ".asByteArray()" + separator + paramDefinition.parameterName + ".size, ") + } + TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE -> { + paramsBuilder.append(paramDefinition.parameterName + ".asByteArray()" + separator) + } + TypeDefinition.LONG -> { + paramsBuilder.append(paramDefinition.parameterName + separator) + } + TypeDefinition.INT -> { + paramsBuilder.append(paramDefinition.parameterName + separator) + } + TypeDefinition.STRING -> { + paramsBuilder.append(paramDefinition.parameterName + separator) + } + } + } + + } + paramsBuilder.append(')') + return paramsBuilder.toString() + } + + } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/SharedCreators.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/SharedCreators.kt index 132e6a3..2d27595 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/SharedCreators.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/SharedCreators.kt @@ -2,10 +2,8 @@ package com.ionspin.kotlin.crypto.generator.libsodium.generator import com.ionspin.kotlin.crypto.generator.libsodium.definitions.ClassDefinition import com.ionspin.kotlin.crypto.generator.libsodium.definitions.FunctionDefinition -import com.ionspin.kotlin.crypto.generator.libsodium.definitions.KotlinFileDefinition -import com.squareup.kotlinpoet.FileSpec +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.InnerClassDefinition import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.ParameterSpec import com.squareup.kotlinpoet.TypeSpec /** @@ -13,14 +11,13 @@ import com.squareup.kotlinpoet.TypeSpec * ugljesa.jovanovic@ionspin.com * on 31-Jul-2020 */ -fun createClass(classDefinition: ClassDefinition, multiplatformModifier: MultiplatformModifier, methodCreator : (FunctionDefinition) -> FunSpec) : TypeSpec { +fun createClass( + classDefinition: ClassDefinition, + multiplatformModifier: MultiplatformModifier, + methodCreator: (FunctionDefinition) -> FunSpec +): TypeSpec { val commonClassBuilder = TypeSpec.classBuilder(classDefinition.name) commonClassBuilder.modifiers += multiplatformModifier.modifierList - for (innerClassDefinition in classDefinition.innerClasses) { - val innerClassBuilder = TypeSpec.classBuilder(innerClassDefinition.name) - innerClassBuilder.modifiers += multiplatformModifier.modifierList - commonClassBuilder.addType(innerClassBuilder.build()) - } for (methodDefinition in classDefinition.methods) { commonClassBuilder.addFunction(methodCreator(methodDefinition)) } diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt new file mode 100644 index 0000000..e74773c --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt @@ -0,0 +1,19 @@ +package debug.test + +import Sha256State +import kotlin.Int +import kotlin.UByteArray + +expect class Sha256State + +expect class Hashing { + fun init(state: Sha256State): Int +} + +expect class GenericHash { + fun init( + state: UByteArray, + key: UByteArray, + outlen: Int + ): Int +} diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt new file mode 100644 index 0000000..719a140 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt @@ -0,0 +1,29 @@ +package debug.test + +import Sha256State +import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazycode.lazysodium.interfaces.Hash +import kotlin.Int +import kotlin.UByteArray + +val sodium: SodiumJava = SodiumJava() + +actual typealias Sha256State = Hash.State256 + +actual class Hashing { + actual fun init(state: Sha256State): Int { + println("Debug") + return sodium.crypto_hash_sha256_init(state) + } +} + +actual class GenericHash { + actual fun init( + state: UByteArray, + key: UByteArray, + outlen: Int + ): Int { + println("Debug") + return sodium.crypto_generichash_init(state.asByteArray(), key.asByteArray(), key.size, outlen) + } +} diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/Sha256State.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/Sha256State.kt new file mode 100644 index 0000000..494f035 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/Sha256State.kt @@ -0,0 +1,5 @@ +package debug.test + +import libsodium.crypto_hash_sha256_state + +actual typealias Sha256State = crypto_hash_sha256_state