1 /* data-mem.c - A memory based data object.
2 Copyright (C) 2002, 2003, 2004, 2007 g10 Code GmbH
4 This file is part of GPGME.
6 GPGME is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of
9 the License, or (at your option) any later version.
11 GPGME is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
39 mem_read (gpgme_data_t dh, void *buffer, size_t size)
41 size_t amt = dh->data.mem.length - dh->data.mem.offset;
50 src = dh->data.mem.buffer ? dh->data.mem.buffer : dh->data.mem.orig_buffer;
51 memcpy (buffer, src + dh->data.mem.offset, amt);
52 dh->data.mem.offset += amt;
58 mem_write (gpgme_data_t dh, const void *buffer, size_t size)
62 if (!dh->data.mem.buffer && dh->data.mem.orig_buffer)
64 size_t new_size = dh->data.mem.size;
67 if (new_size < dh->data.mem.offset + size)
68 new_size = dh->data.mem.offset + size;
70 new_buffer = malloc (new_size);
73 memcpy (new_buffer, dh->data.mem.orig_buffer, dh->data.mem.length);
75 dh->data.mem.buffer = new_buffer;
76 dh->data.mem.size = new_size;
79 unused = dh->data.mem.size - dh->data.mem.offset;
82 /* Allocate a large enough buffer with exponential backoff. */
83 #define INITIAL_ALLOC 512
84 size_t new_size = dh->data.mem.size
85 ? (2 * dh->data.mem.size) : INITIAL_ALLOC;
88 if (new_size < dh->data.mem.offset + size)
89 new_size = dh->data.mem.offset + size;
91 new_buffer = realloc (dh->data.mem.buffer, new_size);
92 if (!new_buffer && new_size > dh->data.mem.offset + size)
94 /* Maybe we were too greedy, try again. */
95 new_size = dh->data.mem.offset + size;
96 new_buffer = realloc (dh->data.mem.buffer, new_size);
100 dh->data.mem.buffer = new_buffer;
101 dh->data.mem.size = new_size;
104 memcpy (dh->data.mem.buffer + dh->data.mem.offset, buffer, size);
105 dh->data.mem.offset += size;
106 if (dh->data.mem.length < dh->data.mem.offset)
107 dh->data.mem.length = dh->data.mem.offset;
113 mem_seek (gpgme_data_t dh, off_t offset, int whence)
118 if (offset < 0 || offset > dh->data.mem.length)
120 gpg_err_set_errno (EINVAL);
123 dh->data.mem.offset = offset;
126 if ((offset > 0 && dh->data.mem.length - dh->data.mem.offset < offset)
127 || (offset < 0 && dh->data.mem.offset < -offset))
129 gpg_err_set_errno (EINVAL);
132 dh->data.mem.offset += offset;
135 if (offset > 0 || -offset > dh->data.mem.length)
137 gpg_err_set_errno (EINVAL);
140 dh->data.mem.offset = dh->data.mem.length - offset;
143 gpg_err_set_errno (EINVAL);
146 return dh->data.mem.offset;
151 mem_release (gpgme_data_t dh)
153 if (dh->data.mem.buffer)
154 free (dh->data.mem.buffer);
158 static struct _gpgme_data_cbs mem_cbs =
168 /* Create a new data buffer and return it in R_DH. */
170 gpgme_data_new (gpgme_data_t *r_dh)
173 TRACE_BEG (DEBUG_DATA, "gpgme_data_new", r_dh);
175 err = _gpgme_data_new (r_dh, &mem_cbs);
178 return TRACE_ERR (err);
180 return TRACE_SUC1 ("dh=%p", *r_dh);
184 /* Create a new data buffer filled with SIZE bytes starting from
185 BUFFER. If COPY is zero, copying is delayed until necessary, and
186 the data is taken from the original location when needed. */
188 gpgme_data_new_from_mem (gpgme_data_t *r_dh, const char *buffer,
189 size_t size, int copy)
192 TRACE_BEG4 (DEBUG_DATA, "gpgme_data_new_from_mem", r_dh,
193 "buffer=%p, size=%u, copy=%i (%s)", buffer, size,
194 copy, copy ? "yes" : "no");
196 err = _gpgme_data_new (r_dh, &mem_cbs);
198 return TRACE_ERR (err);
202 char *bufcpy = malloc (size);
205 int saved_errno = errno;
206 _gpgme_data_release (*r_dh);
207 return TRACE_ERR (gpg_error_from_errno (saved_errno));
209 memcpy (bufcpy, buffer, size);
210 (*r_dh)->data.mem.buffer = bufcpy;
213 (*r_dh)->data.mem.orig_buffer = buffer;
215 (*r_dh)->data.mem.size = size;
216 (*r_dh)->data.mem.length = size;
217 return TRACE_SUC1 ("dh=%p", *r_dh);
221 /* Destroy the data buffer DH and return a pointer to its content.
222 The memory has be to released with gpgme_free() by the user. It's
223 size is returned in R_LEN. */
225 gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len)
229 TRACE_BEG1 (DEBUG_DATA, "gpgme_data_release_and_get_mem", dh,
232 if (!dh || dh->cbs != &mem_cbs)
234 gpgme_data_release (dh);
235 TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
239 str = dh->data.mem.buffer;
240 if (!str && dh->data.mem.orig_buffer)
242 str = malloc (dh->data.mem.length);
245 int saved_errno = errno;
246 gpgme_data_release (dh);
247 TRACE_ERR (gpg_error_from_errno (saved_errno));
250 memcpy (str, dh->data.mem.orig_buffer, dh->data.mem.length);
253 /* Prevent mem_release from releasing the buffer memory. We must
254 not fail from this point. */
255 dh->data.mem.buffer = NULL;
258 *r_len = dh->data.mem.length;
260 gpgme_data_release (dh);
264 TRACE_SUC2 ("buffer=%p, len=%u", str, *r_len);
268 TRACE_SUC1 ("buffer=%p", str);
274 /* Release the memory returned by gpgme_data_release_and_get_mem(). */
276 gpgme_free (void *buffer)
278 TRACE (DEBUG_DATA, "gpgme_free", buffer);