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
37 mem_read (gpgme_data_t dh, void *buffer, size_t size)
39 size_t amt = dh->data.mem.length - dh->data.mem.offset;
48 src = dh->data.mem.buffer ? dh->data.mem.buffer : dh->data.mem.orig_buffer;
49 memcpy (buffer, src + dh->data.mem.offset, amt);
50 dh->data.mem.offset += amt;
56 mem_write (gpgme_data_t dh, const void *buffer, size_t size)
60 if (!dh->data.mem.buffer && dh->data.mem.orig_buffer)
62 size_t new_size = dh->data.mem.size;
65 if (new_size < dh->data.mem.offset + size)
66 new_size = dh->data.mem.offset + size;
68 new_buffer = malloc (new_size);
71 memcpy (new_buffer, dh->data.mem.orig_buffer, dh->data.mem.length);
73 dh->data.mem.buffer = new_buffer;
74 dh->data.mem.size = new_size;
77 unused = dh->data.mem.size - dh->data.mem.offset;
80 /* Allocate a large enough buffer with exponential backoff. */
81 #define INITIAL_ALLOC 512
82 size_t new_size = dh->data.mem.size
83 ? (2 * dh->data.mem.size) : INITIAL_ALLOC;
86 if (new_size < dh->data.mem.offset + size)
87 new_size = dh->data.mem.offset + size;
89 new_buffer = realloc (dh->data.mem.buffer, new_size);
90 if (!new_buffer && new_size > dh->data.mem.offset + size)
92 /* Maybe we were too greedy, try again. */
93 new_size = dh->data.mem.offset + size;
94 new_buffer = realloc (dh->data.mem.buffer, new_size);
98 dh->data.mem.buffer = new_buffer;
99 dh->data.mem.size = new_size;
102 memcpy (dh->data.mem.buffer + dh->data.mem.offset, buffer, size);
103 dh->data.mem.offset += size;
104 if (dh->data.mem.length < dh->data.mem.offset)
105 dh->data.mem.length = dh->data.mem.offset;
111 mem_seek (gpgme_data_t dh, off_t offset, int whence)
116 if (offset < 0 || offset > dh->data.mem.length)
118 gpg_err_set_errno (EINVAL);
121 dh->data.mem.offset = offset;
124 if ((offset > 0 && dh->data.mem.length - dh->data.mem.offset < offset)
125 || (offset < 0 && dh->data.mem.offset < -offset))
127 gpg_err_set_errno (EINVAL);
130 dh->data.mem.offset += offset;
133 if (offset > 0 || -offset > dh->data.mem.length)
135 gpg_err_set_errno (EINVAL);
138 dh->data.mem.offset = dh->data.mem.length - offset;
141 gpg_err_set_errno (EINVAL);
144 return dh->data.mem.offset;
149 mem_release (gpgme_data_t dh)
151 if (dh->data.mem.buffer)
152 free (dh->data.mem.buffer);
156 static struct _gpgme_data_cbs mem_cbs =
166 /* Create a new data buffer and return it in R_DH. */
168 gpgme_data_new (gpgme_data_t *r_dh)
171 TRACE_BEG (DEBUG_DATA, "gpgme_data_new", r_dh);
173 err = _gpgme_data_new (r_dh, &mem_cbs);
176 return TRACE_ERR (err);
178 return TRACE_SUC1 ("dh=%p", *r_dh);
182 /* Create a new data buffer filled with SIZE bytes starting from
183 BUFFER. If COPY is zero, copying is delayed until necessary, and
184 the data is taken from the original location when needed. */
186 gpgme_data_new_from_mem (gpgme_data_t *r_dh, const char *buffer,
187 size_t size, int copy)
190 TRACE_BEG4 (DEBUG_DATA, "gpgme_data_new_from_mem", r_dh,
191 "buffer=%p, size=%u, copy=%i (%s)", buffer, size,
192 copy, copy ? "yes" : "no");
194 err = _gpgme_data_new (r_dh, &mem_cbs);
196 return TRACE_ERR (err);
200 char *bufcpy = malloc (size);
203 int saved_errno = errno;
204 _gpgme_data_release (*r_dh);
205 return TRACE_ERR (gpg_error_from_errno (saved_errno));
207 memcpy (bufcpy, buffer, size);
208 (*r_dh)->data.mem.buffer = bufcpy;
211 (*r_dh)->data.mem.orig_buffer = buffer;
213 (*r_dh)->data.mem.size = size;
214 (*r_dh)->data.mem.length = size;
215 return TRACE_SUC1 ("dh=%p", *r_dh);
219 /* Destroy the data buffer DH and return a pointer to its content.
220 The memory has be to released with gpgme_free() by the user. It's
221 size is returned in R_LEN. */
223 gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len)
227 TRACE_BEG1 (DEBUG_DATA, "gpgme_data_release_and_get_mem", dh,
230 if (!dh || dh->cbs != &mem_cbs)
232 gpgme_data_release (dh);
233 TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
237 str = dh->data.mem.buffer;
238 if (!str && dh->data.mem.orig_buffer)
240 str = malloc (dh->data.mem.length);
243 int saved_errno = errno;
244 gpgme_data_release (dh);
245 TRACE_ERR (gpg_error_from_errno (saved_errno));
248 memcpy (str, dh->data.mem.orig_buffer, dh->data.mem.length);
251 /* Prevent mem_release from releasing the buffer memory. We must
252 not fail from this point. */
253 dh->data.mem.buffer = NULL;
256 *r_len = dh->data.mem.length;
258 gpgme_data_release (dh);
262 TRACE_SUC2 ("buffer=%p, len=%u", str, *r_len);
266 TRACE_SUC1 ("buffer=%p", str);
272 /* Release the memory returned by gpgme_data_release_and_get_mem(). */
274 gpgme_free (void *buffer)
276 TRACE (DEBUG_DATA, "gpgme_free", buffer);