diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2020-01-29 23:48:24 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2020-01-29 23:48:24 +0100 |
commit | b9b6533bd5394cd5cdb6b91b5c5ca7a02e3ea199 (patch) | |
tree | 6efa2009011ab08bbc24167a845d3d075edc6149 | |
parent | 81e1b39d2ea9ffa07f11aed3f230a7f26792058f (diff) |
openpgp-ffi: Add a general reader interface.
-rw-r--r-- | openpgp-ffi/examples/Makefile | 1 | ||||
-rw-r--r-- | openpgp-ffi/examples/reader-cookie.c | 19 | ||||
-rw-r--r-- | openpgp-ffi/include/sequoia/io.h | 12 | ||||
-rw-r--r-- | openpgp-ffi/src/io.rs | 36 |
4 files changed, 68 insertions, 0 deletions
diff --git a/openpgp-ffi/examples/Makefile b/openpgp-ffi/examples/Makefile index c8de2c1f..faf6962d 100644 --- a/openpgp-ffi/examples/Makefile +++ b/openpgp-ffi/examples/Makefile @@ -14,6 +14,7 @@ EXAMPLES = \ generate-key \ type-safety-demo use-after-free-demo immutable-reference-demo \ writer-cookie \ + reader-cookie \ CFLAGS = -I../include -O0 -g -Wall -Werror LDFLAGS = -L$(CARGO_TARGET_DIR)/debug -lsequoia_openpgp_ffi diff --git a/openpgp-ffi/examples/reader-cookie.c b/openpgp-ffi/examples/reader-cookie.c new file mode 100644 index 00000000..c9795fd1 --- /dev/null +++ b/openpgp-ffi/examples/reader-cookie.c @@ -0,0 +1,19 @@ +#include <assert.h> +#include <stdio.h> +#include <unistd.h> +#include <sequoia/openpgp.h> + +int +main (int argv, char **argc) +{ + /* As an example, use read(2) as the callback. */ + pgp_reader_t r = pgp_reader_from_callback ((pgp_reader_cb_t) read, + (void *) 0); + + pgp_cert_t cert = pgp_cert_from_reader (NULL, r); + assert (cert); + + pgp_cert_free (cert); + pgp_reader_free (r); + return 0; +} diff --git a/openpgp-ffi/include/sequoia/io.h b/openpgp-ffi/include/sequoia/io.h index 8cce06c5..81d0093a 100644 --- a/openpgp-ffi/include/sequoia/io.h +++ b/openpgp-ffi/include/sequoia/io.h @@ -29,6 +29,18 @@ pgp_reader_t pgp_reader_from_fd (int fd); pgp_reader_t pgp_reader_from_bytes (const uint8_t *buf, size_t len); /*/ +/// The callback type for the generic callback-based reader interface. +/*/ +typedef ssize_t (*pgp_reader_cb_t) (void *cookie, const void *buf, size_t len); + +/*/ +/// Creates an reader from a callback and cookie. +/// +/// This reader calls the given callback to write data. +/*/ +pgp_reader_t pgp_reader_from_callback (pgp_reader_cb_t, void *); + +/*/ /// Frees a reader. /*/ void pgp_reader_free (pgp_reader_t reader); diff --git a/openpgp-ffi/src/io.rs b/openpgp-ffi/src/io.rs index e3488e07..afa3a74e 100644 --- a/openpgp-ffi/src/io.rs +++ b/openpgp-ffi/src/io.rs @@ -73,6 +73,42 @@ pub extern "C" fn pgp_reader_from_bytes(buf: *const u8, ReaderKind::Generic(Box::new(Cursor::new(buf))).move_into_raw() } +/// The callback type for the generic callback-based reader interface. +type ReaderCallbackFn = fn(*mut c_void, *const c_void, size_t) -> ssize_t; + +/// Creates an reader from a callback and cookie. +/// +/// This reader calls the given callback to write data. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" +fn pgp_reader_from_callback(cb: ReaderCallbackFn, + cookie: *mut c_void) + -> *mut Reader { + let r: Box<dyn io::Read> = Box::new(ReaderCallback { + cb, cookie, + }); + ReaderKind::Generic(r).move_into_raw() +} + +/// A generic callback-based reader implementation. +struct ReaderCallback { + cb: ReaderCallbackFn, + cookie: *mut c_void, +} + +impl Read for ReaderCallback { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let r = + (self.cb)(self.cookie, buf.as_mut_ptr() as *mut c_void, buf.len()); + if r < 0 { + use std::io as stdio; + Err(stdio::Error::new(stdio::ErrorKind::Other, + "Unknown error in read callback")) + } else { + Ok(r as usize) + } + } +} + /// Reads up to `len` bytes into `buf`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_reader_read(errp: Option<&mut *mut crate::error::Error>, |