summaryrefslogtreecommitdiffstats
path: root/openpgp-ffi
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-01-29 22:57:39 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-01-29 23:48:15 +0100
commit81e1b39d2ea9ffa07f11aed3f230a7f26792058f (patch)
tree509b61e4b3e0535e82d4277e809e3023ec8cf839 /openpgp-ffi
parente5ee74691f21f46bdc30556a6b67ecf5f9532ece (diff)
openpgp-ffi: Add a general writer interface.
Diffstat (limited to 'openpgp-ffi')
-rw-r--r--openpgp-ffi/examples/Makefile1
-rw-r--r--openpgp-ffi/examples/writer-cookie.c31
-rw-r--r--openpgp-ffi/include/sequoia/io.h12
-rw-r--r--openpgp-ffi/src/io.rs42
4 files changed, 86 insertions, 0 deletions
diff --git a/openpgp-ffi/examples/Makefile b/openpgp-ffi/examples/Makefile
index f5dd0f8c..c8de2c1f 100644
--- a/openpgp-ffi/examples/Makefile
+++ b/openpgp-ffi/examples/Makefile
@@ -13,6 +13,7 @@ EXAMPLES = \
decrypt-with \
generate-key \
type-safety-demo use-after-free-demo immutable-reference-demo \
+ writer-cookie \
CFLAGS = -I../include -O0 -g -Wall -Werror
LDFLAGS = -L$(CARGO_TARGET_DIR)/debug -lsequoia_openpgp_ffi
diff --git a/openpgp-ffi/examples/writer-cookie.c b/openpgp-ffi/examples/writer-cookie.c
new file mode 100644
index 00000000..b22f1fc3
--- /dev/null
+++ b/openpgp-ffi/examples/writer-cookie.c
@@ -0,0 +1,31 @@
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sequoia/openpgp.h>
+
+int
+main (int argv, char **argc)
+{
+ pgp_status_t rc;
+
+ /* First, generate the key. */
+ pgp_cert_builder_t builder = pgp_cert_builder_new ();
+ pgp_cert_builder_set_cipher_suite (&builder, PGP_CERT_CIPHER_SUITE_CV25519);
+
+ pgp_cert_t cert;
+ pgp_signature_t revocation;
+ pgp_cert_builder_generate (NULL, builder, &cert, &revocation);
+ assert (cert);
+ assert (revocation);
+ pgp_signature_free (revocation); /* Free the generated revocation. */
+
+ /* As an example, use write(2) as the callback. */
+ pgp_writer_t w = pgp_writer_from_callback ((pgp_writer_cb_t) write,
+ (void *) 1);
+ rc = pgp_cert_serialize (NULL, cert, w);
+ assert (rc == PGP_STATUS_SUCCESS);
+
+ pgp_cert_free (cert);
+ pgp_writer_free (w);
+ return 0;
+}
diff --git a/openpgp-ffi/include/sequoia/io.h b/openpgp-ffi/include/sequoia/io.h
index 103116ae..8cce06c5 100644
--- a/openpgp-ffi/include/sequoia/io.h
+++ b/openpgp-ffi/include/sequoia/io.h
@@ -84,6 +84,18 @@ pgp_writer_t pgp_writer_from_bytes (uint8_t *buf, size_t len);
pgp_writer_t pgp_writer_alloc (void **buf, size_t *len);
/*/
+/// The callback type for the generic callback-based writer interface.
+/*/
+typedef ssize_t (*pgp_writer_cb_t) (void *cookie, const void *buf, size_t len);
+
+/*/
+/// Creates an writer from a callback and cookie.
+///
+/// This writer calls the given callback to write data.
+/*/
+pgp_writer_t pgp_writer_from_callback (pgp_writer_cb_t, void *);
+
+/*/
/// Frees a writer.
/*/
void pgp_writer_free (pgp_writer_t writer);
diff --git a/openpgp-ffi/src/io.rs b/openpgp-ffi/src/io.rs
index f0314e19..e3488e07 100644
--- a/openpgp-ffi/src/io.rs
+++ b/openpgp-ffi/src/io.rs
@@ -228,6 +228,48 @@ impl Write for WriterAlloc {
}
}
+/// The callback type for the generic callback-based writer interface.
+type WriterCallbackFn = fn(*mut c_void, *const c_void, size_t) -> ssize_t;
+
+/// Creates an writer from a callback and cookie.
+///
+/// This writer calls the given callback to write data.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
+fn pgp_writer_from_callback(cb: WriterCallbackFn,
+ cookie: *mut c_void)
+ -> *mut Writer {
+ let w: Box<dyn io::Write> = Box::new(WriterCallback {
+ cb, cookie,
+ });
+ w.move_into_raw()
+}
+
+/// A generic callback-based writer implementation.
+struct WriterCallback {
+ cb: WriterCallbackFn,
+ cookie: *mut c_void,
+}
+
+impl Write for WriterCallback {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let r =
+ (self.cb)(self.cookie, buf.as_ptr() as *const c_void, buf.len());
+ if r < 0 {
+ use std::io as stdio;
+ Err(stdio::Error::new(stdio::ErrorKind::Other,
+ "Unknown error in write callback"))
+ } else {
+ Ok(r as usize)
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ // Do nothing.
+ // XXX: Should we add a callback for that?
+ Ok(())
+ }
+}
+
/// Writes up to `len` bytes of `buf` into `writer`.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn pgp_writer_write(errp: Option<&mut *mut crate::error::Error>,