2002-10-09 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Wed, 9 Oct 2002 12:26:00 +0000 (12:26 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Wed, 9 Oct 2002 12:26:00 +0000 (12:26 +0000)
* data.h, data-user.c, data-stream.c, data-mem.c, data-fd.c,
data-compat.c: New file.  Really check them in this time, completes
2002-10-08 change.

gpgme/ChangeLog
gpgme/data-compat.c [new file with mode: 0644]
gpgme/data-fd.c [new file with mode: 0644]
gpgme/data-mem.c [new file with mode: 0644]
gpgme/data-stream.c [new file with mode: 0644]
gpgme/data-user.c [new file with mode: 0644]
gpgme/data.h [new file with mode: 0644]

index ce49669..5dba90e 100644 (file)
@@ -1,5 +1,9 @@
 2002-10-09  Marcus Brinkmann  <marcus@g10code.de>
 
+       * data.h, data-user.c, data-stream.c, data-mem.c, data-fd.c,
+       data-compat.c: New file.  Really check them in this time, completes
+       2002-10-08 change.
+
        * rungpg.h (GpgStatusHandler): Rename type to GpgmeStatusHandler
        and move to ...
        * types.h (GpgmeStatusHandler): ... here.
diff --git a/gpgme/data-compat.c b/gpgme/data-compat.c
new file mode 100644 (file)
index 0000000..6eec787
--- /dev/null
@@ -0,0 +1,193 @@
+/* data-mem.c - A memory based data object.
+ *      Copyright (C) 2002 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "data.h"
+#include "util.h"
+
+\f
+/* Create a new data buffer filled with LENGTH bytes starting from
+   OFFSET within the file FNAME or stream STREAM (exactly one must be
+   non-zero).  */
+GpgmeError
+gpgme_data_new_from_filepart (GpgmeData *dh, const char *fname, FILE *stream,
+                             off_t offset, size_t length)
+{
+  GpgmeError err;
+  char *buf = NULL;
+
+  if (stream && fname)
+    return mk_error (Invalid_Value);
+
+  if (fname)
+    stream = fopen (fname, "rb");
+  if (!stream)
+    return mk_error (File_Error);
+
+  if (fseek (stream, offset, SEEK_SET))
+    goto ferr;
+
+  buf = malloc (length);
+  if (!buf)
+    goto ferr;
+
+  while (fread (buf, length, 1, stream) < 1
+        && ferror (stream) && errno == EINTR);
+  if (ferror (stream))
+    {
+      if (buf)
+       free (buf);
+      goto ferr;
+    }
+
+  if (fname)
+    fclose (stream);
+
+  err = gpgme_data_new (dh);
+  if (err)
+    {
+      if (buf)
+       free (buf);
+      return err;
+    }
+
+  (*dh)->data.mem.buffer = buf;
+  (*dh)->data.mem.size = length;
+  (*dh)->data.mem.length = length;
+  return 0;
+
+ ferr:
+  {
+    int saved_errno = errno;
+    if (fname)
+      fclose (stream);
+    errno = saved_errno;
+    return mk_error (File_Error);
+  }
+}
+
+\f
+/* Create a new data buffer filled with the content of file FNAME.
+   COPY must be non-zero (delayed reads are not supported yet).  */
+GpgmeError
+gpgme_data_new_from_file (GpgmeData *dh, const char *fname, int copy)
+{
+  struct stat statbuf;
+
+  if (!fname || !copy)
+    return mk_error (Invalid_Value);
+
+  if (stat (fname, &statbuf) < 0)
+    return mk_error (File_Error);
+
+  return gpgme_data_new_from_filepart (dh, fname, NULL, 0, statbuf.st_size);
+}
+
+\f
+static int
+gpgme_error_to_errno (GpgmeError err)
+{
+  switch (err)
+    {
+    case mk_error (EOF):
+      return 0;
+    case mk_error (Out_Of_Core):
+      errno = ENOMEM;
+      return -1;
+    case mk_error (Invalid_Value):
+      errno = EINVAL;
+      return -1;
+    case mk_error (Busy):
+      errno = EBUSY;
+      return -1;
+    case mk_error (Not_Implemented):
+      errno = EOPNOTSUPP;
+      return -1;
+    default:
+      /* XXX Yeah, well.  */
+      errno = EINVAL;
+      return -1;
+    }
+}
+
+static int
+old_user_read (GpgmeData dh, void *buffer, size_t size)
+{
+  size_t amt;
+  GpgmeError err = (*dh->data.old_user.cb) (dh->data.old_user.handle,
+                                           buffer, size, &amt);
+  if (err)
+    return gpgme_error_to_errno (err);
+  return amt;
+}
+
+
+static off_t
+old_user_seek (GpgmeData dh, off_t offset, int whence)
+{
+  GpgmeError err;
+  if (whence != SEEK_SET || offset)
+    return EINVAL;
+  err = (*dh->data.old_user.cb) (dh->data.old_user.handle, NULL, 0, NULL);
+  if (err)
+    return gpgme_error_to_errno (err);
+  return 0;
+}
+
+
+static struct gpgme_data_cbs old_user_cbs =
+  {
+    old_user_read,
+    NULL,
+    old_user_seek,
+    NULL
+  };
+
+
+/* Create a new data buffer which retrieves the data from the callback
+   function READ_CB.  */
+GpgmeError
+gpgme_data_new_with_read_cb (GpgmeData *dh,
+                             int (*read_cb) (void *, char *, size_t, size_t *),
+                             void *read_cb_value)
+{
+  GpgmeError err = _gpgme_data_new (dh, &old_user_cbs);
+  if (err)
+    return err;
+
+  (*dh)->data.old_user.cb = read_cb;
+  (*dh)->data.old_user.handle = read_cb_value;
+  return 0;
+}
+
+\f
+GpgmeError
+gpgme_data_rewind (GpgmeData dh)
+{
+  return (gpgme_data_seek (dh, 0, SEEK_SET) == -1)
+    ? mk_error (File_Error) : 0;
+}
diff --git a/gpgme/data-fd.c b/gpgme/data-fd.c
new file mode 100644 (file)
index 0000000..037183d
--- /dev/null
@@ -0,0 +1,70 @@
+/* data-fd.c - A file descripor based data object.
+ *      Copyright (C) 2002 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "data.h"
+
+\f
+static int
+fd_read (GpgmeData dh, void *buffer, size_t size)
+{
+  return read (dh->data.fd, buffer, size);
+}
+
+
+static ssize_t
+fd_write (GpgmeData dh, const void *buffer, size_t size)
+{
+  return write (dh->data.fd, buffer, size);
+}
+
+
+static off_t
+fd_seek (GpgmeData dh, off_t offset, int whence)
+{
+  return lseek (dh->data.fd, offset, whence);
+}
+
+
+static struct gpgme_data_cbs fd_cbs =
+  {
+    fd_read,
+    fd_write,
+    fd_seek,
+    NULL
+  };
+
+\f
+GpgmeError
+gpgme_data_new_from_fd (GpgmeData *dh, int fd)
+{
+  GpgmeError err = _gpgme_data_new (dh, &fd_cbs);
+  if (err)
+    return err;
+
+  (*dh)->data.fd = fd;
+  return 0;
+}
diff --git a/gpgme/data-mem.c b/gpgme/data-mem.c
new file mode 100644 (file)
index 0000000..0afd116
--- /dev/null
@@ -0,0 +1,266 @@
+/* data-mem.c - A memory based data object.
+ *      Copyright (C) 2002 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "data.h"
+#include "util.h"
+
+\f
+static int
+mem_read (GpgmeData dh, void *buffer, size_t size)
+{
+  size_t amt = dh->data.mem.length - dh->data.mem.offset;
+  const char *src;
+
+  if (!amt)
+    return 0;
+
+  if (size < amt)
+    amt = size;
+
+  src = dh->data.mem.buffer ? dh->data.mem.buffer : dh->data.mem.orig_buffer;
+  memcpy (buffer, src + dh->data.mem.offset, amt);
+  dh->data.mem.offset += amt;
+  return amt;
+}
+
+
+static ssize_t
+mem_write (GpgmeData dh, const void *buffer, size_t size)
+{
+  size_t unused;
+
+  if (!dh->data.mem.buffer && dh->data.mem.orig_buffer)
+    {
+      size_t new_size = dh->data.mem.size;
+      char *new_buffer;
+
+      if (new_size < dh->data.mem.offset + size)
+       new_size = dh->data.mem.offset + size;
+
+      new_buffer = malloc (new_size);
+      if (!new_buffer)
+       return -1;
+      dh->data.mem.buffer = new_buffer;      
+      dh->data.mem.size = new_size;
+    }
+
+  unused = dh->data.mem.size - dh->data.mem.offset;
+  if (unused < size)
+    {
+      /* Allocate a large enough buffer with exponential backoff.  */
+#define INITIAL_ALLOC 512
+      size_t new_size = dh->data.mem.size
+       ? (2 * dh->data.mem.size) : INITIAL_ALLOC;
+      char *new_buffer;
+
+      if (new_size < dh->data.mem.offset + size)
+       new_size = dh->data.mem.offset + size;
+
+      new_buffer = realloc (dh->data.mem.buffer, new_size);
+      if (!new_buffer && new_size > dh->data.mem.offset + size)
+       {
+         /* Maybe we were too greedy, try again.  */
+         new_size = dh->data.mem.offset + size;
+         new_buffer = realloc (dh->data.mem.buffer, new_size);
+       }
+      if (!new_buffer)
+       return -1;
+      dh->data.mem.buffer = new_buffer;
+      dh->data.mem.size = new_size;
+    }
+
+  memcpy (dh->data.mem.buffer + dh->data.mem.offset, buffer, size);
+  dh->data.mem.offset += size;
+  if (dh->data.mem.length < dh->data.mem.offset)
+    dh->data.mem.length = dh->data.mem.offset;
+  return size;
+}
+
+
+static off_t
+mem_seek (GpgmeData dh, off_t offset, int whence)
+{
+  switch (whence)
+    {
+    case SEEK_SET:
+      if (offset < 0 || offset > dh->data.mem.length)
+       {
+         errno = EINVAL;
+         return -1;
+       }
+      dh->data.mem.offset = offset;
+      break;
+    case SEEK_CUR:
+      if ((offset > 0 && dh->data.mem.length - dh->data.mem.offset < offset)
+         || (offset < 0 && dh->data.mem.offset < -offset)) 
+       {
+         errno = EINVAL;
+         return -1;
+       }
+      dh->data.mem.offset += offset;
+      break;
+    case SEEK_END:
+      if (offset > 0 || -offset > dh->data.mem.length)
+       {
+         errno = EINVAL;
+         return -1;
+       }
+      dh->data.mem.offset = dh->data.mem.length - offset;
+      break;
+    default:
+      errno = EINVAL;
+      return -1;
+    }
+  return dh->data.mem.offset;
+}
+
+
+static int
+mem_release (GpgmeData dh)
+{
+  if (dh->data.mem.buffer)
+    free (dh->data.mem.buffer);
+  return 0;
+}
+
+
+static struct gpgme_data_cbs mem_cbs =
+  {
+    mem_read,
+    mem_write,
+    mem_seek,
+    mem_release
+  };
+
+\f
+GpgmeError
+gpgme_data_new (GpgmeData *dh)
+{
+  GpgmeError err = _gpgme_data_new (dh, &mem_cbs);
+  if (err)
+    return err;
+
+  return 0;
+}
+
+
+/* Create a new data buffer filled with SIZE bytes starting from
+   BUFFER.  If COPY is zero, copying is delayed until necessary, and
+   the data is taken from the original location when needed.  */
+GpgmeError
+gpgme_data_new_from_mem (GpgmeData *dh, const char *buffer,
+                        size_t size, int copy)
+{
+  GpgmeError err = _gpgme_data_new (dh, &mem_cbs);
+  if (err)
+    return err;
+
+  if (copy)
+    {
+      char *bufcpy = malloc (size);
+      if (!bufcpy)
+       _gpgme_data_release (*dh);
+      memcpy (bufcpy, buffer, size);
+      (*dh)->data.mem.buffer = bufcpy;
+    }
+  else
+    (*dh)->data.mem.orig_buffer = buffer;
+  
+  (*dh)->data.mem.size = size;
+  (*dh)->data.mem.length = size;
+  return 0;
+}
+
+
+/* This function does make sense when we know that it contains no nil
+   chars and if the underlying data object is memory based.  */
+char *
+_gpgme_data_get_as_string (GpgmeData dh)
+{
+  char *dst = NULL;
+  const char *src = NULL;
+
+  assert (dh->cbs == &mem_cbs);
+
+  src = dh->data.mem.buffer;
+  if (!src)
+    src = dh->data.mem.orig_buffer;
+  dst = malloc (dh->data.mem.length + 1);
+  if (dst)
+    {
+      if (src)
+       memcpy (dst, src, dh->data.mem.length);
+      dst[dh->data.mem.length] = '\0';
+    }
+  return dst;
+}
+
+
+char *
+gpgme_data_release_and_get_mem (GpgmeData dh, size_t *r_len)
+{
+  char *str = NULL;
+
+  if (!dh || dh->cbs != &mem_cbs)
+    return NULL;
+
+  str = dh->data.mem.buffer;
+  if (!str && dh->data.mem.orig_buffer)
+    {
+      str = malloc (dh->data.mem.length);
+      if (!str)
+       return NULL;
+      memcpy (str, dh->data.mem.orig_buffer, dh->data.mem.length);
+    }
+
+  if (r_len)
+    *r_len = dh->data.mem.length;
+
+  return str;
+}
+
+
+/* This function does make sense when we know that it contains no nil
+   chars and if the underlying data object is memory based.  */
+char *
+_gpgme_data_release_and_return_string (GpgmeData dh)
+{
+  char *str = NULL;
+
+  if (!dh)
+    return NULL;
+
+  assert (dh->cbs == &mem_cbs);
+  if (gpgme_data_write (dh, "", 1) == 1)
+    str = gpgme_data_release_and_get_mem (dh, NULL);
+  else
+    gpgme_data_release (dh);
+
+  return str;
+}
diff --git a/gpgme/data-stream.c b/gpgme/data-stream.c
new file mode 100644 (file)
index 0000000..33d4498
--- /dev/null
@@ -0,0 +1,76 @@
+/* data-stream.c - A memory based data object.
+ *      Copyright (C) 2002 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "data.h"
+
+\f
+static int
+stream_read (GpgmeData dh, void *buffer, size_t size)
+{
+  size_t amt = fread (buffer, 1, size, dh->data.stream);
+  if (amt > 0)
+    return amt;
+  return ferror (dh->data.stream) ? -1 : 0;
+}
+
+
+static ssize_t
+stream_write (GpgmeData dh, const void *buffer, size_t size)
+{
+  size_t amt = fwrite (buffer, 1, size, dh->data.stream);
+  if (amt > 0)
+    return amt;
+  return ferror (dh->data.stream) ? -1 : 0;
+}
+
+
+static off_t
+stream_seek (GpgmeData dh, off_t offset, int whence)
+{
+  return fseek (dh->data.stream, offset, whence);
+}
+
+
+static struct gpgme_data_cbs stream_cbs =
+  {
+    stream_read,
+    stream_write,
+    stream_seek,
+    NULL
+  };
+
+\f
+GpgmeError
+gpgme_data_new_from_stream (GpgmeData *dh, FILE *stream)
+{
+  GpgmeError err = _gpgme_data_new (dh, &stream_cbs);
+  if (err)
+    return err;
+
+  (*dh)->data.stream = stream;
+  return 0;
+}
diff --git a/gpgme/data-user.c b/gpgme/data-user.c
new file mode 100644 (file)
index 0000000..dd0e570
--- /dev/null
@@ -0,0 +1,78 @@
+/* data-user.c - A user callback based data object.
+ *      Copyright (C) 2002 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#include "data.h"
+
+\f
+static int
+user_read (GpgmeData dh, void *buffer, size_t size)
+{
+  return (*dh->data.user.cbs->read) (dh->data.user.handle, buffer, size);
+}
+
+
+static ssize_t
+user_write (GpgmeData dh, const void *buffer, size_t size)
+{
+  return (*dh->data.user.cbs->write) (dh->data.user.handle, buffer, size);
+}
+
+
+static off_t
+user_seek (GpgmeData dh, off_t offset, int whence)
+{
+  return (*dh->data.user.cbs->seek) (dh->data.user.handle, offset, whence);
+}
+
+
+static int
+user_release (GpgmeData dh)
+{
+  (*dh->data.user.cbs->release) (dh->data.user.handle);
+  return 0;
+}
+
+
+static struct gpgme_data_cbs user_cbs =
+  {
+    user_read,
+    user_write,
+    user_seek,
+    user_release
+  };
+
+\f
+GpgmeError
+gpgme_data_new_from_cbs (GpgmeData *dh, struct GpgmeDataCbs *cbs, void *handle)
+{
+  GpgmeError err = _gpgme_data_new (dh, &user_cbs);
+  if (err)
+    return err;
+
+  (*dh)->data.user.cbs = cbs;
+  (*dh)->data.user.handle = handle;
+  return 0;
+}
diff --git a/gpgme/data.h b/gpgme/data.h
new file mode 100644 (file)
index 0000000..6791015
--- /dev/null
@@ -0,0 +1,118 @@
+/* data.h - Internal data object abstraction interface.
+ *      Copyright (C) 2002 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef DATA_H
+#define DATA_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <limits.h>
+
+#include "gpgme.h"
+
+\f
+/* Read up to SIZE bytes into buffer BUFFER from the data object with
+   the handle DH.  Return the number of characters read, 0 on EOF and
+   -1 on error.  If an error occurs, errno is set.  */
+typedef int (*gpgme_data_read_cb) (GpgmeData dh, void *buffer, size_t size);
+
+/* Write up to SIZE bytes from buffer BUFFER to the data object with
+   the handle DH.  Return the number of characters written, or -1 on
+   error.  If an error occurs, errno is set.  */
+typedef ssize_t (*gpgme_data_write_cb) (GpgmeData dh, const void *buffer,
+                                       size_t size);
+
+/* Set the current position from where the next read or write starts
+   in the data object with the handle DH to OFFSET, relativ to
+   WHENCE.  */
+typedef off_t (*gpgme_data_seek_cb) (GpgmeData dh, off_t offset, int whence);
+
+/* Release the data object with the handle DH.  */
+typedef int (*gpgme_data_release_cb) (GpgmeData dh);
+
+struct gpgme_data_cbs
+{
+  gpgme_data_read_cb read;
+  gpgme_data_write_cb write;
+  gpgme_data_seek_cb seek;
+  gpgme_data_release_cb release;
+};
+
+struct gpgme_data_s
+{
+  struct gpgme_data_cbs *cbs;
+  GpgmeDataEncoding encoding;
+
+#ifdef PIPE_BUF
+#define BUFFER_SIZE PIPE_BUF
+#else
+#ifdef _POSIX_PIPE_BUF
+#define BUFFER_SIZE _POSIX_PIPE_BUF
+#else
+#define BUFFER_SIZE 512
+#endif
+#endif
+  char pending[BUFFER_SIZE];
+  int pending_len;
+
+  union
+  {
+    /* For gpgme_data_new_from_fd.  */
+    int fd;
+
+    /* For gpgme_data_new_from_stream.  */
+    FILE *stream;
+
+    /* For gpgme_data_new_from_cbs.  */
+    struct
+    {
+      struct GpgmeDataCbs *cbs;
+      void *handle;
+    } user;
+
+    /* For gpgme_data_new_from_mem.  */
+    struct
+    {
+      char *buffer;
+      const char *orig_buffer;
+      /* Allocated size of BUFFER.  */
+      size_t size;
+      size_t length;
+      size_t offset;
+    } mem;
+
+    /* For gpgme_data_new_from_read_cb.  */
+    struct
+    {
+      int (*cb) (void *, char *, size_t, size_t *);
+      void *handle;
+    } old_user;
+  } data;
+};
+
+\f
+GpgmeError _gpgme_data_new (GpgmeData *r_dh, struct gpgme_data_cbs *cbs);
+
+void _gpgme_data_release (GpgmeData dh);
+
+#endif /* DATA_H */