summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-01-29 23:48:24 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-01-29 23:48:24 +0100
commitb9b6533bd5394cd5cdb6b91b5c5ca7a02e3ea199 (patch)
tree6efa2009011ab08bbc24167a845d3d075edc6149
parent81e1b39d2ea9ffa07f11aed3f230a7f26792058f (diff)
openpgp-ffi: Add a general reader interface.
-rw-r--r--openpgp-ffi/examples/Makefile1
-rw-r--r--openpgp-ffi/examples/reader-cookie.c19
-rw-r--r--openpgp-ffi/include/sequoia/io.h12
-rw-r--r--openpgp-ffi/src/io.rs36
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>,