summaryrefslogtreecommitdiffstats
path: root/ffi/src/openpgp/armor.rs
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-01-17 11:11:27 +0100
committerJustus Winter <justus@sequoia-pgp.org>2019-01-17 16:48:28 +0100
commit3f58832474a4b270e136544016a401ef773ac065 (patch)
treec617160250c3040ca964c1b72ab5957cd872b82f /ffi/src/openpgp/armor.rs
parent38b4108cc1eac851ac17932c5c33623dd535bebb (diff)
openpgp-ffi: New crate.
- This creates a new crate, 'sequoia-openpgp-ffi', and moves a handful of functions from 'sequoia-ffi' to it. - The 'sequoia-ffi' crate is a superset of the 'sequoia-openpgp-ffi' crate. This is accomplished by some include! magic. - My first attempt involved having 'sequoia-ffi' depend on 'sequoia-openpgp-ffi', so that the former just re-exports the symbols. However, that turned out to be unreliable, and might be not what we want, because it could also duplicate parts of Rust's standard library. - Fixes #144.
Diffstat (limited to 'ffi/src/openpgp/armor.rs')
-rw-r--r--ffi/src/openpgp/armor.rs347
1 files changed, 0 insertions, 347 deletions
diff --git a/ffi/src/openpgp/armor.rs b/ffi/src/openpgp/armor.rs
deleted file mode 100644
index 1a42c369..00000000
--- a/ffi/src/openpgp/armor.rs
+++ /dev/null
@@ -1,347 +0,0 @@
-//! ASCII Armor.
-//!
-//! Wraps [`sequoia-openpgp::armor`].
-//!
-//! [`sequoia-openpgp::armor`]: ../../../sequoia_openpgp/armor/index.html
-
-use std::mem::size_of;
-use std::ptr;
-use std::slice;
-use std::io::{Read, Write};
-use libc::{self, uint8_t, c_char, c_int, size_t};
-
-extern crate sequoia_openpgp;
-use self::sequoia_openpgp::armor;
-
-/// Represents a (key, value) pair in an armor header.
-#[repr(C)]
-pub struct ArmorHeader {
- key: *const c_char,
- value: *const c_char,
-}
-
-fn int_to_kind(kind: c_int) -> Option<armor::Kind> {
- match kind {
- 0 => None,
- 1 => Some(armor::Kind::Message),
- 2 => Some(armor::Kind::PublicKey),
- 3 => Some(armor::Kind::SecretKey),
- 4 => Some(armor::Kind::Signature),
- 5 => Some(armor::Kind::File),
- _ => panic!("Bad kind: {}", kind),
- }
-}
-
-fn kind_to_int(kind: Option<armor::Kind>) -> c_int {
- match kind {
- None => 0,
- Some(armor::Kind::Message) => 1,
- Some(armor::Kind::PublicKey) => 2,
- Some(armor::Kind::SecretKey) => 3,
- Some(armor::Kind::Signature) => 4,
- Some(armor::Kind::File) => 5,
- }
-}
-
-/// Constructs a new filter for the given type of data.
-///
-/// A filter that strips ASCII Armor from a stream of data.
-///
-/// # Example
-///
-/// ```c
-/// #define _GNU_SOURCE
-/// #include <assert.h>
-/// #include <error.h>
-/// #include <stdio.h>
-/// #include <stdlib.h>
-/// #include <string.h>
-///
-/// #include <sequoia.h>
-///
-/// const char *armored =
-/// "-----BEGIN PGP ARMORED FILE-----\n"
-/// "Key0: Value0\n"
-/// "Key1: Value1\n"
-/// "\n"
-/// "SGVsbG8gd29ybGQh\n"
-/// "=s4Gu\n"
-/// "-----END PGP ARMORED FILE-----\n";
-///
-/// int
-/// main (int argc, char **argv)
-/// {
-/// sq_error_t err;
-/// sq_reader_t bytes;
-/// sq_reader_t armor;
-/// sq_armor_kind_t kind;
-/// char message[12];
-/// sq_armor_header_t *header;
-/// size_t header_len;
-///
-/// bytes = sq_reader_from_bytes ((uint8_t *) armored, strlen (armored));
-/// armor = sq_armor_reader_new (bytes, SQ_ARMOR_KIND_ANY);
-///
-/// header = sq_armor_reader_headers (&err, armor, &header_len);
-/// if (header == NULL)
-/// error (1, 0, "Getting headers failed: %s", sq_error_string (err));
-///
-/// assert (header_len == 2);
-/// assert (strcmp (header[0].key, "Key0") == 0
-/// && strcmp (header[0].value, "Value0") == 0);
-/// assert (strcmp (header[1].key, "Key1") == 0
-/// && strcmp (header[1].value, "Value1") == 0);
-/// for (size_t i = 0; i < header_len; i++)
-/// {
-/// free (header[i].key);
-/// free (header[i].value);
-/// }
-/// free (header);
-///
-/// kind = sq_armor_reader_kind (armor);
-/// assert (kind == SQ_ARMOR_KIND_FILE);
-///
-/// if (sq_reader_read (&err, armor, (uint8_t *) message, 12) < 0)
-/// error (1, 0, "Reading failed: %s", sq_error_string (err));
-///
-/// assert (memcmp (message, "Hello world!", 12) == 0);
-///
-/// sq_reader_free (armor);
-/// sq_reader_free (bytes);
-/// return 0;
-/// }
-/// ```
-#[::ffi_catch_abort] #[no_mangle]
-pub extern "system" fn sq_armor_reader_new(inner: *mut Box<Read>,
- kind: c_int)
- -> *mut Box<Read> {
- let inner = ffi_param_ref_mut!(inner);
- let kind = int_to_kind(kind);
-
- box_raw!(Box::new(armor::Reader::new(inner, kind)))
-}
-
-/// Creates a `Reader` from a file.
-#[::ffi_catch_abort] #[no_mangle]
-pub extern "system" fn sq_armor_reader_from_file(errp: Option<&mut *mut failure::Error>,
- filename: *const c_char,
- kind: c_int)
- -> *mut Box<Read> {
- ffi_make_fry_from_errp!(errp);
- let filename = ffi_param_cstr!(filename).to_string_lossy().into_owned();
- let kind = int_to_kind(kind);
-
- ffi_try_box!(armor::Reader::from_file(&filename, kind)
- .map(|r| Box::new(r))
- .map_err(|e| e.into()))
-}
-
-/// Creates a `Reader` from a buffer.
-#[::ffi_catch_abort] #[no_mangle]
-pub extern "system" fn sq_armor_reader_from_bytes(b: *const uint8_t, len: size_t,
- kind: c_int)
- -> *mut Box<Read> {
- assert!(!b.is_null());
- let buf = unsafe {
- slice::from_raw_parts(b, len as usize)
- };
- let kind = int_to_kind(kind);
-
- box_raw!(Box::new(armor::Reader::from_bytes(buf, kind)))
-}
-
-/// Returns the kind of data this reader is for.
-///
-/// Useful if the kind of data is not known in advance. If the header
-/// has not been encountered yet (try reading some data first!), this
-/// function returns SQ_ARMOR_KIND_ANY.
-///
-/// # Example
-///
-/// See [this] example.
-///
-/// [this]: fn.sq_armor_reader_new.html
-#[::ffi_catch_abort] #[no_mangle]
-pub extern "system" fn sq_armor_reader_kind(reader: *mut Box<Read>)
- -> c_int {
- // We need to downcast `reader`. To do that, we need to do a
- // little dance. We will momentarily take ownership of `reader`,
- // wrapping it in a Box again. Then, at the end of the function,
- // we will leak it again.
- let reader = ffi_param_move!(reader as *mut Box<armor::Reader>);
- let kind = kind_to_int(reader.kind());
- Box::into_raw(reader);
- kind
-}
-
-/// Returns the armored headers.
-///
-/// The tuples contain a key and a value.
-///
-/// Note: if a key occurs multiple times, then there are multiple
-/// entries in the vector with the same key; values with the same
-/// key are *not* combined.
-///
-/// The returned array and the strings in the headers have been
-/// allocated with `malloc`, and the caller is responsible for freeing
-/// both the array and the strings.
-///
-/// # Example
-///
-/// See [this] example.
-///
-/// [this]: fn.sq_armor_reader_new.html
-#[::ffi_catch_abort] #[no_mangle]
-pub extern "system" fn sq_armor_reader_headers(errp: Option<&mut *mut failure::Error>,
- reader: *mut Box<Read>,
- len: *mut size_t)
- -> *mut ArmorHeader {
- ffi_make_fry_from_errp!(errp);
- let len = ffi_param_ref_mut!(len);
-
- // We need to downcast `reader`. To do that, we need to do a
- // little dance. We will momentarily take ownership of `reader`,
- // wrapping it in a Box again. Then, at the end of the function,
- // we will leak it again.
- let mut reader = ffi_param_move!(reader as *mut Box<armor::Reader>);
-
- // We need to be extra careful here in order not to keep ownership
- // of `reader` in case of errors.
- let result = match reader.headers().map_err(|e| e.into()) {
- Ok(headers) => {
- // Allocate space for the result.
- let buf = unsafe {
- libc::calloc(headers.len(), size_of::<ArmorHeader>())
- as *mut ArmorHeader
- };
- let sl = unsafe {
- slice::from_raw_parts_mut(buf, headers.len())
- };
- for (i, (key, value)) in headers.iter().enumerate() {
- sl[i].key = strdup(key);
- sl[i].value = strdup(value);
- }
-
- *len = headers.len();
- buf
- },
- Err(e) => {
- if let Some(errp) = errp {
- *errp = box_raw!(e);
- }
- ptr::null_mut()
- },
- };
-
- // Release temporary ownership.
- Box::into_raw(reader);
- result
-}
-
-/// Creates a zero-terminated C string from a &str allocated using
-/// malloc.
-fn strdup(s: &str) -> *mut c_char {
- let b = s.as_bytes();
- let len = b.len() + 1;
- let dup = unsafe {
- libc::malloc(len) as *mut c_char
- };
- let sl = unsafe {
- slice::from_raw_parts_mut(dup as *mut uint8_t, len)
- };
- sl[..len-1].copy_from_slice(b);
- sl[len-1] = 0;
- dup
-}
-
-/// Constructs a new filter for the given type of data.
-///
-/// A filter that applies ASCII Armor to the data written to it.
-///
-/// # Example
-///
-/// ```c
-/// #define _GNU_SOURCE
-/// #include <assert.h>
-/// #include <error.h>
-/// #include <stdio.h>
-/// #include <stdlib.h>
-/// #include <string.h>
-///
-/// #include <sequoia.h>
-///
-/// int
-/// main (int argc, char **argv)
-/// {
-/// void *buf = NULL;
-/// size_t len = 0;
-/// sq_writer_t alloc;
-/// sq_writer_t armor;
-/// sq_error_t err;
-///
-/// char *message = "Hello world!";
-/// sq_armor_header_t header[2] = {
-/// { "Key0", "Value0" },
-/// { "Key1", "Value1" },
-/// };
-///
-/// alloc = sq_writer_alloc (&buf, &len);
-/// armor = sq_armor_writer_new (&err, alloc, SQ_ARMOR_KIND_FILE, header, 2);
-/// if (armor == NULL)
-/// error (1, 0, "Creating armor writer failed: %s", sq_error_string (err));
-///
-/// if (sq_writer_write (&err, armor, (uint8_t *) message, strlen (message)) < 0)
-/// error (1, 0, "Writing failed: %s", sq_error_string (err));
-//
-/// sq_writer_free (armor);
-/// sq_writer_free (alloc);
-///
-/// assert (len == 114);
-/// assert (memcmp (buf,
-/// "-----BEGIN PGP ARMORED FILE-----\n"
-/// "Key0: Value0\n"
-/// "Key1: Value1\n"
-/// "\n"
-/// "SGVsbG8gd29ybGQh\n"
-/// "=s4Gu\n"
-/// "-----END PGP ARMORED FILE-----\n",
-/// len) == 0);
-///
-/// free (buf);
-/// return 0;
-/// }
-/// ```
-#[::ffi_catch_abort] #[no_mangle]
-pub extern "system" fn sq_armor_writer_new
- (errp: Option<&mut *mut failure::Error>,
- inner: *mut Box<Write>,
- kind: c_int,
- header: *const ArmorHeader,
- header_len: size_t)
- -> *mut Box<Write>
-{
- ffi_make_fry_from_errp!(errp);
- let inner = ffi_param_ref_mut!(inner);
- let kind = int_to_kind(kind).expect("KIND must not be SQ_ARMOR_KIND_ANY");
-
- let mut header_ = Vec::new();
- if header_len > 0 {
- let headers = ffi_param_ref!(header);
- let headers = unsafe {
- slice::from_raw_parts(headers, header_len)
- };
- for header in headers {
- header_.push(
- (ffi_param_cstr!(header.key).to_string_lossy(),
- ffi_param_cstr!(header.value).to_string_lossy())
- );
- }
- }
-
- let header: Vec<(&str, &str)> =
- header_.iter().map(|h| (h.0.as_ref(), h.1.as_ref())).collect();
-
- ffi_try_box!(armor::Writer::new(inner, kind, &header)
- .map(|r| Box::new(r))
- .map_err(|e| e.into()))
-}