simple-c2pa

This is a fork of https://gitlab.com/guardianproject/proofmode/simple-c2pa
git clone git://archive.git.mtrnord.blog/mtrnords-photography-manager/simple-c2pa.git
Log | Files | Refs | README | LICENSE

commit 810c34f081ae38f38b0c02de6de5817592b5dcfb
parent c939223b2e0d4999a0f3d31c6205dc7e9294d99a
Author: Darren Clarke <darren@redaranj.com>
Date:   Wed,  6 Dec 2023 10:20:50 +0100

Re-integrate mobile repos

Diffstat:
M.gitlab-ci.yml | 4++--
MMakefile.toml | 4+++-
APackage.swift | 27+++++++++++++++++++++++++++
R.gitlab-ci.android.yml -> android/.gitlab-ci.yml | 0
Aandroid/project/.gitignore | 16++++++++++++++++
Aandroid/project/build.gradle.kts | 6++++++
Aandroid/project/gradle.properties | 23+++++++++++++++++++++++
Aandroid/project/gradle/wrapper/gradle-wrapper.properties | 6++++++
Aandroid/project/gradlew | 185+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aandroid/project/gradlew.bat | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aandroid/project/settings.gradle.kts | 17+++++++++++++++++
Aandroid/project/simple_c2pa/build.gradle.kts | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aandroid/project/simple_c2pa/consumer-rules.pro | 0
Aandroid/project/simple_c2pa/proguard-rules.pro | 25+++++++++++++++++++++++++
Aandroid/project/simple_c2pa/src/main/AndroidManifest.xml | 4++++
R.gitlab-ci.apple.yml -> apple/.gitlab-ci.yml | 0
Aapple/src/SimpleC2PA.swift | 1837+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17 files changed, 2308 insertions(+), 3 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml @@ -4,9 +4,9 @@ stages: trigger_apple: stage: triggers trigger: - include: ".gitlab-ci.apple.yml" + include: "apple/.gitlab-ci.yml" trigger_android: stage: triggers trigger: - include: ".gitlab-ci.android.yml" + include: "android/.gitlab-ci.yml" diff --git a/Makefile.toml b/Makefile.toml @@ -75,7 +75,7 @@ cross build --target aarch64-linux-android --release [tasks.android-build-bindings] script = ''' -cargo build --target x86_64-linux-android +cross build --target x86_64-linux-android cargo run --bin uniffi-bindgen generate --language kotlin --library ./target/x86_64-linux-android/debug/libsimple_c2pa.so --out-dir ${BINDINGS_DIR}/kotlin ''' @@ -102,3 +102,5 @@ dependencies = [ "android-build-bindings", "android-assemble-aar-files", ] + +[tasks.create-release] diff --git a/Package.swift b/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version:5.5 +import PackageDescription + +let package = Package( + name: "SimpleC2PA", + platforms: [ + .iOS(.v15), + ], + products: [ + .library( + name: "SimpleC2PA", + targets: ["SimpleC2PA"] + ), + ], + dependencies: [], + targets: [ + .binaryTarget( + name: "SimpleC2PAFramework", + url: "https://gitlab.com/api/v4/projects/51891540/packages/generic/simple_c2pa/apple-v0.174/SimpleC2PA.xcframework.zip", + ), + .target( + name: "SimpleC2PA", + path: "apple/src" + dependencies: [ "SimpleC2PAFramework" ] + ), + ] +) diff --git a/.gitlab-ci.android.yml b/android/.gitlab-ci.yml diff --git a/android/project/.gitignore b/android/project/.gitignore @@ -0,0 +1,16 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +**/build/ +/captures +.externalNativeBuild +.cxx +local.properties +.idea diff --git a/android/project/build.gradle.kts b/android/project/build.gradle.kts @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id("org.jetbrains.kotlin.android") version "1.9.0" apply false + id("com.android.library") version "8.1.3" apply false +} + diff --git a/android/project/gradle.properties b/android/project/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true diff --git a/android/project/gradle/wrapper/gradle-wrapper.properties b/android/project/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Nov 16 17:31:21 CET 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/project/gradlew b/android/project/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/android/project/gradlew.bat b/android/project/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/project/settings.gradle.kts b/android/project/settings.gradle.kts @@ -0,0 +1,17 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "simple_c2pa" +include(":simple_c2pa") diff --git a/android/project/simple_c2pa/build.gradle.kts b/android/project/simple_c2pa/build.gradle.kts @@ -0,0 +1,68 @@ +import org.gradle.api.publish.maven.MavenPublication + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + `maven-publish` +} + +android { + namespace = "info.guardianproject.simple_c2pa" + compileSdk = 33 + + defaultConfig { + minSdk = 21 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation("androidx.core:core-ktx:1.9.0") + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.8.0") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + implementation("net.java.dev.jna:jna:5.13.0@aar") +} + +publishing { + publications { + create<MavenPublication>("release") { + artifact("$buildDir/outputs/aar/${project.name}-release.aar") + groupId = "info.guardianproject" + artifactId = "simple_c2pa" + version = "0.0.5" + } + } + repositories { + maven { + url = uri("https://gitlab.com/api/v4/projects/52243488/packages/maven") + credentials { + this.username = findProperty("MAVEN_USERNAME") as String? + this.password = findProperty("MAVEN_PASSWORD") as String? + } + } + } +} + diff --git a/android/project/simple_c2pa/consumer-rules.pro b/android/project/simple_c2pa/consumer-rules.pro diff --git a/android/project/simple_c2pa/proguard-rules.pro b/android/project/simple_c2pa/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-dontwarn java.awt.* +-keep class com.sun.jna.* { *; } +-keepclassmembers class * extends com.sun.jna.* { public *; } diff --git a/android/project/simple_c2pa/src/main/AndroidManifest.xml b/android/project/simple_c2pa/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android"> + +</manifest> diff --git a/.gitlab-ci.apple.yml b/apple/.gitlab-ci.yml diff --git a/apple/src/SimpleC2PA.swift b/apple/src/SimpleC2PA.swift @@ -0,0 +1,1836 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(SimpleC2PAFFI) +import SimpleC2PAFFI +#endif + +fileprivate extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func from(_ ptr: UnsafeBufferPointer<UInt8>) -> RustBuffer { + try! rustCall { ffi_simple_c2pa_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_simple_c2pa_rustbuffer_free(self, $0) } + } +} + +fileprivate extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer<UInt8>) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a library of its own. + +fileprivate extension Data { + init(rustBuffer: RustBuffer) { + // TODO: This copies the buffer. Can we read directly from a + // Rust buffer? + self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +fileprivate func readInt<T: FixedWidthInteger>(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset..<reader.offset + MemoryLayout<T>.size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)}) + reader.offset = range.upperBound + return value.bigEndian +} + +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings +fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array<UInt8> { + let range = reader.offset..<(reader.offset+count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer({ buffer in + reader.data.copyBytes(to: buffer, from: range) + }) + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return Float(bitPattern: try readInt(&reader)) +} + +// Reads a float at the current offset. +fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return Double(bitPattern: try readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +fileprivate func createWriter() -> [UInt8] { + return [] +} + +fileprivate func writeBytes<S>(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +fileprivate func writeInt<T: FixedWidthInteger>(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous go the Rust trait of the same name. +fileprivate protocol FfiConverter { + associatedtype FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } + +extension FfiConverterPrimitive { + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + + public static func lower(_ value: SwiftType) -> FfiType { + return value + } +} + +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} + +extension FfiConverterRustBuffer { + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +fileprivate enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +fileprivate let CALL_SUCCESS: Int8 = 0 +fileprivate let CALL_ERROR: Int8 = 1 +fileprivate let CALL_PANIC: Int8 = 2 +fileprivate let CALL_CANCELLED: Int8 = 3 + +fileprivate extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer.init( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall<T>(_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T { + try makeRustCall(callback, errorHandler: nil) +} + +private func rustCallWithError<T>( + _ errorHandler: @escaping (RustBuffer) throws -> Error, + _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall<T>( + _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T, + errorHandler: ((RustBuffer) throws -> Error)? +) throws -> T { + uniffiEnsureInitialized() + var callStatus = RustCallStatus.init() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> Error)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_PANIC: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + case CALL_CANCELLED: + throw CancellationError() + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +// Public interface members begin here. + + +fileprivate struct FfiConverterUInt8: FfiConverterPrimitive { + typealias FfiType = UInt8 + typealias SwiftType = UInt8 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt8 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: UInt8, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +fileprivate struct FfiConverterDouble: FfiConverterPrimitive { + typealias FfiType = Double + typealias SwiftType = Double + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Double { + return try lift(readDouble(&buf)) + } + + public static func write(_ value: Double, into buf: inout [UInt8]) { + writeDouble(&buf, lower(value)) + } +} + +fileprivate struct FfiConverterBool : FfiConverter { + typealias FfiType = Int8 + typealias SwiftType = Bool + + public static func lift(_ value: Int8) throws -> Bool { + return value != 0 + } + + public static func lower(_ value: Bool) -> Int8 { + return value ? 1 : 0 + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bool { + return try lift(readInt(&buf)) + } + + public static func write(_ value: Bool, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +fileprivate struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() + } + if value.data == nil { + return String() + } + let bytes = UnsafeBufferPointer<UInt8>(start: value.data!, count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + public static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + +fileprivate struct FfiConverterData: FfiConverterRustBuffer { + typealias SwiftType = Data + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Data { + let len: Int32 = try readInt(&buf) + return Data(try readBytes(&buf, count: Int(len))) + } + + public static func write(_ value: Data, into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + writeBytes(&buf, value) + } +} + + +public protocol ApplicationInfoProtocol { + +} + +public class ApplicationInfo: ApplicationInfoProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(name: String, version: String, iconUri: String?) { + self.init(unsafeFromRawPointer: try! rustCall() { + uniffi_simple_c2pa_fn_constructor_applicationinfo_new( + FfiConverterString.lower(name), + FfiConverterString.lower(version), + FfiConverterOptionString.lower(iconUri),$0) +}) + } + + deinit { + try! rustCall { uniffi_simple_c2pa_fn_free_applicationinfo(pointer, $0) } + } + + + + + +} + +public struct FfiConverterTypeApplicationInfo: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = ApplicationInfo + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ApplicationInfo { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: ApplicationInfo, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> ApplicationInfo { + return ApplicationInfo(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: ApplicationInfo) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public func FfiConverterTypeApplicationInfo_lift(_ pointer: UnsafeMutableRawPointer) throws -> ApplicationInfo { + return try FfiConverterTypeApplicationInfo.lift(pointer) +} + +public func FfiConverterTypeApplicationInfo_lower(_ value: ApplicationInfo) -> UnsafeMutableRawPointer { + return FfiConverterTypeApplicationInfo.lower(value) +} + + +public protocol CertificateProtocol { + func getCertificateBytes() throws -> Data + func getPrivateKeyBytes() throws -> Data + +} + +public class Certificate: CertificateProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(certificateData: FileData, privateKeyData: FileData, parentCertificate: Certificate?) { + self.init(unsafeFromRawPointer: try! rustCall() { + uniffi_simple_c2pa_fn_constructor_certificate_new( + FfiConverterTypeFileData.lower(certificateData), + FfiConverterTypeFileData.lower(privateKeyData), + FfiConverterOptionTypeCertificate.lower(parentCertificate),$0) +}) + } + + deinit { + try! rustCall { uniffi_simple_c2pa_fn_free_certificate(pointer, $0) } + } + + + + + + + public func getCertificateBytes() throws -> Data { + return try FfiConverterData.lift( + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_certificate_get_certificate_bytes(self.pointer, $0 + ) +} + ) + } + + public func getPrivateKeyBytes() throws -> Data { + return try FfiConverterData.lift( + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_certificate_get_private_key_bytes(self.pointer, $0 + ) +} + ) + } +} + +public struct FfiConverterTypeCertificate: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Certificate + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Certificate { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: Certificate, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Certificate { + return Certificate(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: Certificate) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public func FfiConverterTypeCertificate_lift(_ pointer: UnsafeMutableRawPointer) throws -> Certificate { + return try FfiConverterTypeCertificate.lift(pointer) +} + +public func FfiConverterTypeCertificate_lower(_ value: Certificate) -> UnsafeMutableRawPointer { + return FfiConverterTypeCertificate.lower(value) +} + + +public protocol CertificateOptionsProtocol { + +} + +public class CertificateOptions: CertificateOptionsProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(key: FileData, certificateType: CertificateType, parentCertificate: Certificate?, emailAddress: String?, pgpFingerprint: String?) { + self.init(unsafeFromRawPointer: try! rustCall() { + uniffi_simple_c2pa_fn_constructor_certificateoptions_new( + FfiConverterTypeFileData.lower(key), + FfiConverterTypeCertificateType.lower(certificateType), + FfiConverterOptionTypeCertificate.lower(parentCertificate), + FfiConverterOptionString.lower(emailAddress), + FfiConverterOptionString.lower(pgpFingerprint),$0) +}) + } + + deinit { + try! rustCall { uniffi_simple_c2pa_fn_free_certificateoptions(pointer, $0) } + } + + + + + +} + +public struct FfiConverterTypeCertificateOptions: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = CertificateOptions + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CertificateOptions { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: CertificateOptions, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> CertificateOptions { + return CertificateOptions(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: CertificateOptions) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public func FfiConverterTypeCertificateOptions_lift(_ pointer: UnsafeMutableRawPointer) throws -> CertificateOptions { + return try FfiConverterTypeCertificateOptions.lift(pointer) +} + +public func FfiConverterTypeCertificateOptions_lower(_ value: CertificateOptions) -> UnsafeMutableRawPointer { + return FfiConverterTypeCertificateOptions.lower(value) +} + + +public protocol ContentCredentialsProtocol { + func addCreatedAssertion() throws + func addCustomAiTrainingAssertions(options: CustomAiTrainingOptions) throws + func addEmailAssertion(email: String, displayName: String) throws + func addExifAssertion(exifData: ExifData) throws + func addInstagramAssertion(username: String, displayName: String) throws + func addJsonAssertion(label: String, json: String) throws + func addPermissiveAiTrainingAssertions() throws + func addPgpAssertion(fingerprint: String, displayName: String) throws + func addPlacedAssertion() throws + func addRestrictedAiTrainingAssertions() throws + func addWebsiteAssertion(url: String) throws + func embedManifest(outputPath: String?) throws -> FileData + func exportManifest(outputPath: String?) throws -> FileData + func signManifest(embed: Bool, outputPath: String?) throws -> FileData + func signManifestWithCertificate(certificate: Certificate, outputFile: FileData) throws + +} + +public class ContentCredentials: ContentCredentialsProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(certificate: Certificate, file: FileData, applicationInfo: ApplicationInfo?) { + self.init(unsafeFromRawPointer: try! rustCall() { + uniffi_simple_c2pa_fn_constructor_contentcredentials_new( + FfiConverterTypeCertificate.lower(certificate), + FfiConverterTypeFileData.lower(file), + FfiConverterOptionTypeApplicationInfo.lower(applicationInfo),$0) +}) + } + + deinit { + try! rustCall { uniffi_simple_c2pa_fn_free_contentcredentials(pointer, $0) } + } + + + + + + + public func addCreatedAssertion() throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_created_assertion(self.pointer, $0 + ) +} + } + + public func addCustomAiTrainingAssertions(options: CustomAiTrainingOptions) throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_custom_ai_training_assertions(self.pointer, + FfiConverterTypeCustomAITrainingOptions.lower(options),$0 + ) +} + } + + public func addEmailAssertion(email: String, displayName: String) throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_email_assertion(self.pointer, + FfiConverterString.lower(email), + FfiConverterString.lower(displayName),$0 + ) +} + } + + public func addExifAssertion(exifData: ExifData) throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_exif_assertion(self.pointer, + FfiConverterTypeExifData.lower(exifData),$0 + ) +} + } + + public func addInstagramAssertion(username: String, displayName: String) throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_instagram_assertion(self.pointer, + FfiConverterString.lower(username), + FfiConverterString.lower(displayName),$0 + ) +} + } + + public func addJsonAssertion(label: String, json: String) throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_json_assertion(self.pointer, + FfiConverterString.lower(label), + FfiConverterString.lower(json),$0 + ) +} + } + + public func addPermissiveAiTrainingAssertions() throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_permissive_ai_training_assertions(self.pointer, $0 + ) +} + } + + public func addPgpAssertion(fingerprint: String, displayName: String) throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_pgp_assertion(self.pointer, + FfiConverterString.lower(fingerprint), + FfiConverterString.lower(displayName),$0 + ) +} + } + + public func addPlacedAssertion() throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_placed_assertion(self.pointer, $0 + ) +} + } + + public func addRestrictedAiTrainingAssertions() throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_restricted_ai_training_assertions(self.pointer, $0 + ) +} + } + + public func addWebsiteAssertion(url: String) throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_add_website_assertion(self.pointer, + FfiConverterString.lower(url),$0 + ) +} + } + + public func embedManifest(outputPath: String?) throws -> FileData { + return try FfiConverterTypeFileData.lift( + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_embed_manifest(self.pointer, + FfiConverterOptionString.lower(outputPath),$0 + ) +} + ) + } + + public func exportManifest(outputPath: String?) throws -> FileData { + return try FfiConverterTypeFileData.lift( + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_export_manifest(self.pointer, + FfiConverterOptionString.lower(outputPath),$0 + ) +} + ) + } + + public func signManifest(embed: Bool, outputPath: String?) throws -> FileData { + return try FfiConverterTypeFileData.lift( + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_sign_manifest(self.pointer, + FfiConverterBool.lower(embed), + FfiConverterOptionString.lower(outputPath),$0 + ) +} + ) + } + + public func signManifestWithCertificate(certificate: Certificate, outputFile: FileData) throws { + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_contentcredentials_sign_manifest_with_certificate(self.pointer, + FfiConverterTypeCertificate.lower(certificate), + FfiConverterTypeFileData.lower(outputFile),$0 + ) +} + } +} + +public struct FfiConverterTypeContentCredentials: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = ContentCredentials + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ContentCredentials { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: ContentCredentials, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> ContentCredentials { + return ContentCredentials(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: ContentCredentials) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public func FfiConverterTypeContentCredentials_lift(_ pointer: UnsafeMutableRawPointer) throws -> ContentCredentials { + return try FfiConverterTypeContentCredentials.lift(pointer) +} + +public func FfiConverterTypeContentCredentials_lower(_ value: ContentCredentials) -> UnsafeMutableRawPointer { + return FfiConverterTypeContentCredentials.lower(value) +} + + +public protocol FileDataProtocol { + func getBytes() throws -> Data + func getPath() throws -> String + +} + +public class FileData: FileDataProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init(path: String?, bytes: Data?, fileName: String?) { + self.init(unsafeFromRawPointer: try! rustCall() { + uniffi_simple_c2pa_fn_constructor_filedata_new( + FfiConverterOptionString.lower(path), + FfiConverterOptionData.lower(bytes), + FfiConverterOptionString.lower(fileName),$0) +}) + } + + deinit { + try! rustCall { uniffi_simple_c2pa_fn_free_filedata(pointer, $0) } + } + + + + + + + public func getBytes() throws -> Data { + return try FfiConverterData.lift( + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_filedata_get_bytes(self.pointer, $0 + ) +} + ) + } + + public func getPath() throws -> String { + return try FfiConverterString.lift( + try + rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_method_filedata_get_path(self.pointer, $0 + ) +} + ) + } +} + +public struct FfiConverterTypeFileData: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = FileData + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FileData { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: FileData, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FileData { + return FileData(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: FileData) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public func FfiConverterTypeFileData_lift(_ pointer: UnsafeMutableRawPointer) throws -> FileData { + return try FfiConverterTypeFileData.lift(pointer) +} + +public func FfiConverterTypeFileData_lower(_ value: FileData) -> UnsafeMutableRawPointer { + return FfiConverterTypeFileData.lower(value) +} + + +public struct CustomAiTrainingOptions { + public var aiTraining: AiDataMiningUsage + public var aiGenerativeTraining: AiDataMiningUsage + public var dataMining: AiDataMiningUsage + public var inference: AiDataMiningUsage + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(aiTraining: AiDataMiningUsage, aiGenerativeTraining: AiDataMiningUsage, dataMining: AiDataMiningUsage, inference: AiDataMiningUsage) { + self.aiTraining = aiTraining + self.aiGenerativeTraining = aiGenerativeTraining + self.dataMining = dataMining + self.inference = inference + } +} + + +extension CustomAiTrainingOptions: Equatable, Hashable { + public static func ==(lhs: CustomAiTrainingOptions, rhs: CustomAiTrainingOptions) -> Bool { + if lhs.aiTraining != rhs.aiTraining { + return false + } + if lhs.aiGenerativeTraining != rhs.aiGenerativeTraining { + return false + } + if lhs.dataMining != rhs.dataMining { + return false + } + if lhs.inference != rhs.inference { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(aiTraining) + hasher.combine(aiGenerativeTraining) + hasher.combine(dataMining) + hasher.combine(inference) + } +} + + +public struct FfiConverterTypeCustomAITrainingOptions: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CustomAiTrainingOptions { + return try CustomAiTrainingOptions( + aiTraining: FfiConverterTypeAIDataMiningUsage.read(from: &buf), + aiGenerativeTraining: FfiConverterTypeAIDataMiningUsage.read(from: &buf), + dataMining: FfiConverterTypeAIDataMiningUsage.read(from: &buf), + inference: FfiConverterTypeAIDataMiningUsage.read(from: &buf) + ) + } + + public static func write(_ value: CustomAiTrainingOptions, into buf: inout [UInt8]) { + FfiConverterTypeAIDataMiningUsage.write(value.aiTraining, into: &buf) + FfiConverterTypeAIDataMiningUsage.write(value.aiGenerativeTraining, into: &buf) + FfiConverterTypeAIDataMiningUsage.write(value.dataMining, into: &buf) + FfiConverterTypeAIDataMiningUsage.write(value.inference, into: &buf) + } +} + + +public func FfiConverterTypeCustomAITrainingOptions_lift(_ buf: RustBuffer) throws -> CustomAiTrainingOptions { + return try FfiConverterTypeCustomAITrainingOptions.lift(buf) +} + +public func FfiConverterTypeCustomAITrainingOptions_lower(_ value: CustomAiTrainingOptions) -> RustBuffer { + return FfiConverterTypeCustomAITrainingOptions.lower(value) +} + + +public struct ExifData { + public var gpsVersionId: String? + public var latitude: String? + public var longitude: String? + public var altitudeRef: UInt8? + public var altitude: String? + public var timestamp: String? + public var speedRef: String? + public var speed: String? + public var directionRef: String? + public var direction: String? + public var destinationBearingRef: String? + public var destinationBearing: String? + public var positioningError: String? + public var exposureTime: String? + public var fNumber: Double? + public var colorSpace: UInt8? + public var digitalZoomRatio: Double? + public var make: String? + public var model: String? + public var lensMake: String? + public var lensModel: String? + public var lensSpecification: [Double]? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(gpsVersionId: String?, latitude: String?, longitude: String?, altitudeRef: UInt8?, altitude: String?, timestamp: String?, speedRef: String?, speed: String?, directionRef: String?, direction: String?, destinationBearingRef: String?, destinationBearing: String?, positioningError: String?, exposureTime: String?, fNumber: Double?, colorSpace: UInt8?, digitalZoomRatio: Double?, make: String?, model: String?, lensMake: String?, lensModel: String?, lensSpecification: [Double]?) { + self.gpsVersionId = gpsVersionId + self.latitude = latitude + self.longitude = longitude + self.altitudeRef = altitudeRef + self.altitude = altitude + self.timestamp = timestamp + self.speedRef = speedRef + self.speed = speed + self.directionRef = directionRef + self.direction = direction + self.destinationBearingRef = destinationBearingRef + self.destinationBearing = destinationBearing + self.positioningError = positioningError + self.exposureTime = exposureTime + self.fNumber = fNumber + self.colorSpace = colorSpace + self.digitalZoomRatio = digitalZoomRatio + self.make = make + self.model = model + self.lensMake = lensMake + self.lensModel = lensModel + self.lensSpecification = lensSpecification + } +} + + +extension ExifData: Equatable, Hashable { + public static func ==(lhs: ExifData, rhs: ExifData) -> Bool { + if lhs.gpsVersionId != rhs.gpsVersionId { + return false + } + if lhs.latitude != rhs.latitude { + return false + } + if lhs.longitude != rhs.longitude { + return false + } + if lhs.altitudeRef != rhs.altitudeRef { + return false + } + if lhs.altitude != rhs.altitude { + return false + } + if lhs.timestamp != rhs.timestamp { + return false + } + if lhs.speedRef != rhs.speedRef { + return false + } + if lhs.speed != rhs.speed { + return false + } + if lhs.directionRef != rhs.directionRef { + return false + } + if lhs.direction != rhs.direction { + return false + } + if lhs.destinationBearingRef != rhs.destinationBearingRef { + return false + } + if lhs.destinationBearing != rhs.destinationBearing { + return false + } + if lhs.positioningError != rhs.positioningError { + return false + } + if lhs.exposureTime != rhs.exposureTime { + return false + } + if lhs.fNumber != rhs.fNumber { + return false + } + if lhs.colorSpace != rhs.colorSpace { + return false + } + if lhs.digitalZoomRatio != rhs.digitalZoomRatio { + return false + } + if lhs.make != rhs.make { + return false + } + if lhs.model != rhs.model { + return false + } + if lhs.lensMake != rhs.lensMake { + return false + } + if lhs.lensModel != rhs.lensModel { + return false + } + if lhs.lensSpecification != rhs.lensSpecification { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(gpsVersionId) + hasher.combine(latitude) + hasher.combine(longitude) + hasher.combine(altitudeRef) + hasher.combine(altitude) + hasher.combine(timestamp) + hasher.combine(speedRef) + hasher.combine(speed) + hasher.combine(directionRef) + hasher.combine(direction) + hasher.combine(destinationBearingRef) + hasher.combine(destinationBearing) + hasher.combine(positioningError) + hasher.combine(exposureTime) + hasher.combine(fNumber) + hasher.combine(colorSpace) + hasher.combine(digitalZoomRatio) + hasher.combine(make) + hasher.combine(model) + hasher.combine(lensMake) + hasher.combine(lensModel) + hasher.combine(lensSpecification) + } +} + + +public struct FfiConverterTypeExifData: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ExifData { + return try ExifData( + gpsVersionId: FfiConverterOptionString.read(from: &buf), + latitude: FfiConverterOptionString.read(from: &buf), + longitude: FfiConverterOptionString.read(from: &buf), + altitudeRef: FfiConverterOptionUInt8.read(from: &buf), + altitude: FfiConverterOptionString.read(from: &buf), + timestamp: FfiConverterOptionString.read(from: &buf), + speedRef: FfiConverterOptionString.read(from: &buf), + speed: FfiConverterOptionString.read(from: &buf), + directionRef: FfiConverterOptionString.read(from: &buf), + direction: FfiConverterOptionString.read(from: &buf), + destinationBearingRef: FfiConverterOptionString.read(from: &buf), + destinationBearing: FfiConverterOptionString.read(from: &buf), + positioningError: FfiConverterOptionString.read(from: &buf), + exposureTime: FfiConverterOptionString.read(from: &buf), + fNumber: FfiConverterOptionDouble.read(from: &buf), + colorSpace: FfiConverterOptionUInt8.read(from: &buf), + digitalZoomRatio: FfiConverterOptionDouble.read(from: &buf), + make: FfiConverterOptionString.read(from: &buf), + model: FfiConverterOptionString.read(from: &buf), + lensMake: FfiConverterOptionString.read(from: &buf), + lensModel: FfiConverterOptionString.read(from: &buf), + lensSpecification: FfiConverterOptionSequenceDouble.read(from: &buf) + ) + } + + public static func write(_ value: ExifData, into buf: inout [UInt8]) { + FfiConverterOptionString.write(value.gpsVersionId, into: &buf) + FfiConverterOptionString.write(value.latitude, into: &buf) + FfiConverterOptionString.write(value.longitude, into: &buf) + FfiConverterOptionUInt8.write(value.altitudeRef, into: &buf) + FfiConverterOptionString.write(value.altitude, into: &buf) + FfiConverterOptionString.write(value.timestamp, into: &buf) + FfiConverterOptionString.write(value.speedRef, into: &buf) + FfiConverterOptionString.write(value.speed, into: &buf) + FfiConverterOptionString.write(value.directionRef, into: &buf) + FfiConverterOptionString.write(value.direction, into: &buf) + FfiConverterOptionString.write(value.destinationBearingRef, into: &buf) + FfiConverterOptionString.write(value.destinationBearing, into: &buf) + FfiConverterOptionString.write(value.positioningError, into: &buf) + FfiConverterOptionString.write(value.exposureTime, into: &buf) + FfiConverterOptionDouble.write(value.fNumber, into: &buf) + FfiConverterOptionUInt8.write(value.colorSpace, into: &buf) + FfiConverterOptionDouble.write(value.digitalZoomRatio, into: &buf) + FfiConverterOptionString.write(value.make, into: &buf) + FfiConverterOptionString.write(value.model, into: &buf) + FfiConverterOptionString.write(value.lensMake, into: &buf) + FfiConverterOptionString.write(value.lensModel, into: &buf) + FfiConverterOptionSequenceDouble.write(value.lensSpecification, into: &buf) + } +} + + +public func FfiConverterTypeExifData_lift(_ buf: RustBuffer) throws -> ExifData { + return try FfiConverterTypeExifData.lift(buf) +} + +public func FfiConverterTypeExifData_lower(_ value: ExifData) -> RustBuffer { + return FfiConverterTypeExifData.lower(value) +} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +public enum AiDataMiningUsage { + + case allowed + case notAllowed + case constrained(constraintInfo: String) +} + +public struct FfiConverterTypeAIDataMiningUsage: FfiConverterRustBuffer { + typealias SwiftType = AiDataMiningUsage + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AiDataMiningUsage { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .allowed + + case 2: return .notAllowed + + case 3: return .constrained( + constraintInfo: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: AiDataMiningUsage, into buf: inout [UInt8]) { + switch value { + + + case .allowed: + writeInt(&buf, Int32(1)) + + + case .notAllowed: + writeInt(&buf, Int32(2)) + + + case let .constrained(constraintInfo): + writeInt(&buf, Int32(3)) + FfiConverterString.write(constraintInfo, into: &buf) + + } + } +} + + +public func FfiConverterTypeAIDataMiningUsage_lift(_ buf: RustBuffer) throws -> AiDataMiningUsage { + return try FfiConverterTypeAIDataMiningUsage.lift(buf) +} + +public func FfiConverterTypeAIDataMiningUsage_lower(_ value: AiDataMiningUsage) -> RustBuffer { + return FfiConverterTypeAIDataMiningUsage.lower(value) +} + + +extension AiDataMiningUsage: Equatable, Hashable {} + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +public enum CertificateType { + + case onlineRoot(organization: String?, validityDays: UInt32?) + case onlineIntermediate(organization: String?, validityDays: UInt32?) + case offlineRoot(organization: String?, validityDays: UInt32?) + case offlineIntermediate(organization: String?, validityDays: UInt32?) + case contentCredentials(organization: String?, validityDays: UInt32?) +} + +public struct FfiConverterTypeCertificateType: FfiConverterRustBuffer { + typealias SwiftType = CertificateType + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CertificateType { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .onlineRoot( + organization: try FfiConverterOptionString.read(from: &buf), + validityDays: try FfiConverterOptionUInt32.read(from: &buf) + ) + + case 2: return .onlineIntermediate( + organization: try FfiConverterOptionString.read(from: &buf), + validityDays: try FfiConverterOptionUInt32.read(from: &buf) + ) + + case 3: return .offlineRoot( + organization: try FfiConverterOptionString.read(from: &buf), + validityDays: try FfiConverterOptionUInt32.read(from: &buf) + ) + + case 4: return .offlineIntermediate( + organization: try FfiConverterOptionString.read(from: &buf), + validityDays: try FfiConverterOptionUInt32.read(from: &buf) + ) + + case 5: return .contentCredentials( + organization: try FfiConverterOptionString.read(from: &buf), + validityDays: try FfiConverterOptionUInt32.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: CertificateType, into buf: inout [UInt8]) { + switch value { + + + case let .onlineRoot(organization,validityDays): + writeInt(&buf, Int32(1)) + FfiConverterOptionString.write(organization, into: &buf) + FfiConverterOptionUInt32.write(validityDays, into: &buf) + + + case let .onlineIntermediate(organization,validityDays): + writeInt(&buf, Int32(2)) + FfiConverterOptionString.write(organization, into: &buf) + FfiConverterOptionUInt32.write(validityDays, into: &buf) + + + case let .offlineRoot(organization,validityDays): + writeInt(&buf, Int32(3)) + FfiConverterOptionString.write(organization, into: &buf) + FfiConverterOptionUInt32.write(validityDays, into: &buf) + + + case let .offlineIntermediate(organization,validityDays): + writeInt(&buf, Int32(4)) + FfiConverterOptionString.write(organization, into: &buf) + FfiConverterOptionUInt32.write(validityDays, into: &buf) + + + case let .contentCredentials(organization,validityDays): + writeInt(&buf, Int32(5)) + FfiConverterOptionString.write(organization, into: &buf) + FfiConverterOptionUInt32.write(validityDays, into: &buf) + + } + } +} + + +public func FfiConverterTypeCertificateType_lift(_ buf: RustBuffer) throws -> CertificateType { + return try FfiConverterTypeCertificateType.lift(buf) +} + +public func FfiConverterTypeCertificateType_lower(_ value: CertificateType) -> RustBuffer { + return FfiConverterTypeCertificateType.lower(value) +} + + +extension CertificateType: Equatable, Hashable {} + + + +public enum SimpleC2paError { + + + + // Simple error enums only carry a message + case Failure(message: String) + + // Simple error enums only carry a message + case Unexpected(message: String) + + + fileprivate static func uniffiErrorHandler(_ error: RustBuffer) throws -> Error { + return try FfiConverterTypeSimpleC2PAError.lift(error) + } +} + + +public struct FfiConverterTypeSimpleC2PAError: FfiConverterRustBuffer { + typealias SwiftType = SimpleC2paError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SimpleC2paError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .Failure( + message: try FfiConverterString.read(from: &buf) + ) + + case 2: return .Unexpected( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: SimpleC2paError, into buf: inout [UInt8]) { + switch value { + + + + + case .Failure(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + case .Unexpected(_ /* message is ignored*/): + writeInt(&buf, Int32(2)) + + + } + } +} + + +extension SimpleC2paError: Equatable, Hashable {} + +extension SimpleC2paError: Error { } + +fileprivate struct FfiConverterOptionUInt8: FfiConverterRustBuffer { + typealias SwiftType = UInt8? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterUInt8.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterUInt8.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionUInt32: FfiConverterRustBuffer { + typealias SwiftType = UInt32? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterUInt32.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterUInt32.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionDouble: FfiConverterRustBuffer { + typealias SwiftType = Double? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterDouble.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterDouble.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { + typealias SwiftType = String? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterString.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterString.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionData: FfiConverterRustBuffer { + typealias SwiftType = Data? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterData.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterData.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeApplicationInfo: FfiConverterRustBuffer { + typealias SwiftType = ApplicationInfo? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeApplicationInfo.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeApplicationInfo.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeCertificate: FfiConverterRustBuffer { + typealias SwiftType = Certificate? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeCertificate.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeCertificate.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionSequenceDouble: FfiConverterRustBuffer { + typealias SwiftType = [Double]? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterSequenceDouble.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterSequenceDouble.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterSequenceDouble: FfiConverterRustBuffer { + typealias SwiftType = [Double] + + public static func write(_ value: [Double], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterDouble.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Double] { + let len: Int32 = try readInt(&buf) + var seq = [Double]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterDouble.read(from: &buf)) + } + return seq + } +} + +public func createCertificate(options: CertificateOptions) throws -> Certificate { + return try FfiConverterTypeCertificate.lift( + try rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_func_create_certificate( + FfiConverterTypeCertificateOptions.lower(options),$0) +} + ) +} + +public func createContentCredentialsCertificate(rootCertificate: Certificate?, organization: String?, validityDays: UInt32?) throws -> Certificate { + return try FfiConverterTypeCertificate.lift( + try rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_func_create_content_credentials_certificate( + FfiConverterOptionTypeCertificate.lower(rootCertificate), + FfiConverterOptionString.lower(organization), + FfiConverterOptionUInt32.lower(validityDays),$0) +} + ) +} + +public func createPrivateKey() throws -> FileData { + return try FfiConverterTypeFileData.lift( + try rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_func_create_private_key($0) +} + ) +} + +public func createRootCertificate(organization: String?, validityDays: UInt32?) throws -> Certificate { + return try FfiConverterTypeCertificate.lift( + try rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_func_create_root_certificate( + FfiConverterOptionString.lower(organization), + FfiConverterOptionUInt32.lower(validityDays),$0) +} + ) +} + +public func requestSignedCertificate(options: CertificateOptions) throws -> String { + return try FfiConverterString.lift( + try rustCallWithError(FfiConverterTypeSimpleC2PAError.lift) { + uniffi_simple_c2pa_fn_func_request_signed_certificate( + FfiConverterTypeCertificateOptions.lower(options),$0) +} + ) +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} +// Use a global variables to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private var initializationResult: InitializationResult { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 24 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_simple_c2pa_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if (uniffi_simple_c2pa_checksum_func_create_certificate() != 34310) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_func_create_content_credentials_certificate() != 25230) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_func_create_private_key() != 61208) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_func_create_root_certificate() != 4408) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_func_request_signed_certificate() != 18474) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_certificate_get_certificate_bytes() != 18161) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_certificate_get_private_key_bytes() != 42096) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_created_assertion() != 61395) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_custom_ai_training_assertions() != 32506) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_email_assertion() != 43840) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_exif_assertion() != 12750) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_instagram_assertion() != 60237) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_json_assertion() != 29285) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_permissive_ai_training_assertions() != 45270) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_pgp_assertion() != 55991) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_placed_assertion() != 41702) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_restricted_ai_training_assertions() != 63406) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_add_website_assertion() != 6602) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_embed_manifest() != 19522) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_export_manifest() != 10130) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_sign_manifest() != 40977) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_contentcredentials_sign_manifest_with_certificate() != 2932) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_filedata_get_bytes() != 59331) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_method_filedata_get_path() != 6887) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_constructor_applicationinfo_new() != 22446) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_constructor_certificate_new() != 33607) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_constructor_certificateoptions_new() != 27700) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_constructor_contentcredentials_new() != 49391) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_simple_c2pa_checksum_constructor_filedata_new() != 65000) { + return InitializationResult.apiChecksumMismatch + } + + return InitializationResult.ok +} + +private func uniffiEnsureInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} +\ No newline at end of file