Line data Source code
1 : /* reader.c - provides the Reader object
2 : * Copyright (C) 2001, 2010, 2012 g10 Code GmbH
3 : *
4 : * This file is part of KSBA.
5 : *
6 : * KSBA is free software; you can redistribute it and/or modify
7 : * it under the terms of either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * KSBA is distributed in the hope that it will be useful, but WITHOUT
22 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
24 : * License for more details.
25 : *
26 : * You should have received a copies of the GNU General Public License
27 : * and the GNU Lesser General Public License along with this program;
28 : * if not, see <http://www.gnu.org/licenses/>.
29 : */
30 :
31 : #include <config.h>
32 : #include <stdio.h>
33 : #include <stdlib.h>
34 : #include <string.h>
35 : #include <assert.h>
36 : #include <errno.h>
37 : #include "util.h"
38 :
39 : #include "ksba.h"
40 : #include "reader.h"
41 :
42 : /**
43 : * ksba_reader_new:
44 : *
45 : * Create a new but uninitialized ksba_reader_t Object. Using this
46 : * reader object in unitialized state does always yield eof.
47 : *
48 : * Return value: ksba_reader_t object or an error code.
49 : **/
50 : gpg_error_t
51 6 : ksba_reader_new (ksba_reader_t *r_r)
52 : {
53 6 : *r_r = xtrycalloc (1, sizeof **r_r);
54 6 : if (!*r_r)
55 0 : return gpg_error_from_errno (errno);
56 6 : return 0;
57 : }
58 :
59 :
60 : /**
61 : * ksba_reader_release:
62 : * @r: Reader Object (or NULL)
63 : *
64 : * Release this object
65 : **/
66 : void
67 6 : ksba_reader_release (ksba_reader_t r)
68 : {
69 6 : if (!r)
70 0 : return;
71 6 : if (r->notify_cb)
72 : {
73 0 : void (*notify_fnc)(void*,ksba_reader_t) = r->notify_cb;
74 :
75 0 : r->notify_cb = NULL;
76 0 : notify_fnc (r->notify_cb_value, r);
77 : }
78 6 : if (r->type == READER_TYPE_MEM)
79 2 : xfree (r->u.mem.buffer);
80 6 : xfree (r->unread.buf);
81 6 : xfree (r);
82 : }
83 :
84 :
85 : /* Set NOTIFY as function to be called by ksba_reader_release before
86 : resources are actually deallocated. NOTIFY_VALUE is passed to the
87 : called function as its first argument. Note that only the last
88 : registered function will be called; passing NULL for NOTIFY removes
89 : the notification. */
90 : gpg_error_t
91 0 : ksba_reader_set_release_notify (ksba_reader_t r,
92 : void (*notify)(void*,ksba_reader_t),
93 : void *notify_value)
94 : {
95 0 : if (!r)
96 0 : return gpg_error (GPG_ERR_INV_VALUE);
97 0 : r->notify_cb = notify;
98 0 : r->notify_cb_value = notify_value;
99 0 : return 0;
100 : }
101 :
102 :
103 : /* Clear the error and eof indicators for READER, so that it can be
104 : continued to use. Also dicards any unread bytes. This is usually
105 : required if the upper layer want to send to send an EOF to indicate
106 : the logical end of one part of a file. If BUFFER and BUFLEN are
107 : not NULL, possible unread data is copied to a newly allocated
108 : buffer and this buffer is assigned to BUFFER, BUFLEN will be set to
109 : the length of the unread bytes. */
110 : gpg_error_t
111 0 : ksba_reader_clear (ksba_reader_t r, unsigned char **buffer, size_t *buflen)
112 : {
113 : size_t n;
114 :
115 0 : if (!r)
116 0 : return gpg_error (GPG_ERR_INV_VALUE);
117 :
118 0 : r->eof = 0;
119 0 : r->error = 0;
120 0 : r->nread = 0;
121 0 : n = r->unread.length;
122 0 : r->unread.length = 0;
123 :
124 0 : if (buffer && buflen)
125 : {
126 0 : *buffer = NULL;
127 0 : *buflen = 0;
128 0 : if (n)
129 : {
130 0 : *buffer = xtrymalloc (n);
131 0 : if (!*buffer)
132 0 : return gpg_error_from_errno (errno);
133 0 : memcpy (*buffer, r->unread.buf, n);
134 0 : *buflen = n;
135 : }
136 : }
137 :
138 0 : return 0;
139 : }
140 :
141 :
142 : gpg_error_t
143 8 : ksba_reader_error (ksba_reader_t r)
144 : {
145 8 : return r? gpg_error_from_errno (r->error) : gpg_error (GPG_ERR_INV_VALUE);
146 : }
147 :
148 : unsigned long
149 312 : ksba_reader_tell (ksba_reader_t r)
150 : {
151 312 : return r? r->nread : 0;
152 : }
153 :
154 :
155 : /**
156 : * ksba_reader_set_mem:
157 : * @r: Reader object
158 : * @buffer: Data
159 : * @length: Length of Data (bytes)
160 : *
161 : * Intialize the reader object with @length bytes from @buffer and set
162 : * the read position to the beginning. It is possible to reuse this
163 : * reader object with another buffer if the reader object has
164 : * already been initialized using this function.
165 : *
166 : * Return value: 0 on success or an error code.
167 : **/
168 : gpg_error_t
169 2 : ksba_reader_set_mem (ksba_reader_t r, const void *buffer, size_t length)
170 : {
171 2 : if (!r || !buffer)
172 0 : return gpg_error (GPG_ERR_INV_VALUE);
173 2 : if (r->type == READER_TYPE_MEM)
174 : { /* Reuse this reader */
175 0 : xfree (r->u.mem.buffer);
176 0 : r->type = 0;
177 : }
178 2 : if (r->type)
179 0 : return gpg_error (GPG_ERR_CONFLICT);
180 :
181 2 : r->u.mem.buffer = xtrymalloc (length);
182 2 : if (!r->u.mem.buffer)
183 0 : return gpg_error (GPG_ERR_ENOMEM);
184 2 : memcpy (r->u.mem.buffer, buffer, length);
185 2 : r->u.mem.size = length;
186 2 : r->u.mem.readpos = 0;
187 2 : r->type = READER_TYPE_MEM;
188 2 : r->eof = 0;
189 :
190 2 : return 0;
191 : }
192 :
193 :
194 : /**
195 : * ksba_reader_set_fd:
196 : * @r: Reader object
197 : * @fd: file descriptor
198 : *
199 : * Initialize the Reader object with a file descriptor, so that read
200 : * operations on this object are excuted on this file descriptor.
201 : *
202 : * Return value:
203 : **/
204 : gpg_error_t
205 0 : ksba_reader_set_fd (ksba_reader_t r, int fd)
206 : {
207 0 : if (!r || fd == -1)
208 0 : return gpg_error (GPG_ERR_INV_VALUE);
209 0 : if (r->type)
210 0 : return gpg_error (GPG_ERR_CONFLICT);
211 :
212 0 : r->eof = 0;
213 0 : r->type = READER_TYPE_FD;
214 0 : r->u.fd = fd;
215 :
216 0 : return 0;
217 : }
218 :
219 : /**
220 : * ksba_reader_set_file:
221 : * @r: Reader object
222 : * @fp: file pointer
223 : *
224 : * Initialize the Reader object with a stdio file pointer, so that read
225 : * operations on this object are excuted on this stream
226 : *
227 : * Return value:
228 : **/
229 : gpg_error_t
230 4 : ksba_reader_set_file (ksba_reader_t r, FILE *fp)
231 : {
232 4 : if (!r || !fp)
233 0 : return gpg_error (GPG_ERR_INV_VALUE);
234 4 : if (r->type)
235 0 : return gpg_error (GPG_ERR_CONFLICT);
236 :
237 4 : r->eof = 0;
238 4 : r->type = READER_TYPE_FILE;
239 4 : r->u.file = fp;
240 4 : return 0;
241 : }
242 :
243 :
244 :
245 : /**
246 : * ksba_reader_set_cb:
247 : * @r: Reader object
248 : * @cb: Callback function
249 : * @cb_value: Value passed to the callback function
250 : *
251 : * Initialize the reader object with a callback function.
252 : * This callback function is defined as:
253 : * <literal>
254 : * typedef int (*cb) (void *cb_value,
255 : * char *buffer, size_t count,
256 : * size_t *nread);
257 : * </literal>
258 : *
259 : * The callback should return a maximium of @count bytes in @buffer
260 : * and the number actually read in @nread. It may return 0 in @nread
261 : * if there are no bytes currently available. To indicate EOF the
262 : * callback should return with an error code of GPG_ERR_EOF and set @nread to
263 : * 0. The callback may support passing %NULL for @buffer and @nread
264 : * and %0 for count as an indication to reset its internal read
265 : * pointer.
266 : *
267 : * Return value: 0 on success or an error code
268 : **/
269 : gpg_error_t
270 0 : ksba_reader_set_cb (ksba_reader_t r,
271 : int (*cb)(void*,char *,size_t,size_t*), void *cb_value )
272 : {
273 0 : if (!r || !cb)
274 0 : return gpg_error (GPG_ERR_INV_VALUE);
275 0 : if (r->type)
276 0 : return gpg_error (GPG_ERR_CONFLICT);
277 :
278 0 : r->eof = 0;
279 0 : r->type = READER_TYPE_CB;
280 0 : r->u.cb.fnc = cb;
281 0 : r->u.cb.value = cb_value;
282 :
283 0 : return 0;
284 : }
285 :
286 :
287 : /**
288 : * ksba_reader_read:
289 : * @r: Readder object
290 : * @buffer: A buffer for returning the data
291 : * @length: The length of this buffer
292 : * @nread: Number of bytes actually read.
293 : *
294 : * Read data from the current read position to the supplied @buffer,
295 : * max. @length bytes are read and the actual number of bytes read are
296 : * returned in @nread. If there are no more bytes available %GPG_ERR_EOF is
297 : * returned and @nread is set to 0.
298 : *
299 : * If a @buffer of NULL is specified, the function does only return
300 : * the number of bytes available and does not move the read pointer.
301 : * This does only work for objects initialized from memory; if the
302 : * object is not capable of this it will return the error
303 : * GPG_ERR_NOT_IMPLEMENTED
304 : *
305 : * Return value: 0 on success, GPG_ERR_EOF or another error code
306 : **/
307 : gpg_error_t
308 984 : ksba_reader_read (ksba_reader_t r, char *buffer, size_t length, size_t *nread)
309 : {
310 : size_t nbytes;
311 :
312 984 : if (!r || !nread)
313 0 : return gpg_error (GPG_ERR_INV_VALUE);
314 :
315 :
316 984 : if (!buffer)
317 : {
318 0 : if (r->type != READER_TYPE_MEM)
319 0 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
320 0 : *nread = r->u.mem.size - r->u.mem.readpos;
321 0 : if (r->unread.buf)
322 0 : *nread += r->unread.length - r->unread.readpos;
323 0 : return *nread? 0 : gpg_error (GPG_ERR_EOF);
324 : }
325 :
326 984 : *nread = 0;
327 :
328 984 : if (r->unread.buf && r->unread.length)
329 : {
330 2 : nbytes = r->unread.length - r->unread.readpos;
331 2 : if (!nbytes)
332 0 : return gpg_error (GPG_ERR_BUG);
333 :
334 2 : if (nbytes > length)
335 1 : nbytes = length;
336 2 : memcpy (buffer, r->unread.buf + r->unread.readpos, nbytes);
337 2 : r->unread.readpos += nbytes;
338 2 : if (r->unread.readpos == r->unread.length)
339 1 : r->unread.readpos = r->unread.length = 0;
340 2 : *nread = nbytes;
341 2 : r->nread += nbytes;
342 2 : return 0;
343 : }
344 :
345 :
346 982 : if (!r->type)
347 : {
348 0 : r->eof = 1;
349 0 : return gpg_error (GPG_ERR_EOF);
350 : }
351 982 : else if (r->type == READER_TYPE_MEM)
352 : {
353 86 : nbytes = r->u.mem.size - r->u.mem.readpos;
354 86 : if (!nbytes)
355 : {
356 2 : r->eof = 1;
357 2 : return gpg_error (GPG_ERR_EOF);
358 : }
359 :
360 84 : if (nbytes > length)
361 82 : nbytes = length;
362 84 : memcpy (buffer, r->u.mem.buffer + r->u.mem.readpos, nbytes);
363 84 : *nread = nbytes;
364 84 : r->nread += nbytes;
365 84 : r->u.mem.readpos += nbytes;
366 : }
367 896 : else if (r->type == READER_TYPE_FILE)
368 : {
369 : size_t n;
370 :
371 896 : if (r->eof)
372 3 : return gpg_error (GPG_ERR_EOF);
373 :
374 893 : if (!length)
375 : {
376 0 : *nread = 0;
377 0 : return 0;
378 : }
379 :
380 893 : n = fread (buffer, 1, length, r->u.file);
381 893 : if (n)
382 : {
383 890 : r->nread += n;
384 890 : *nread = n;
385 : }
386 : else
387 3 : *nread = 0;
388 893 : if (n < length)
389 : {
390 3 : if (ferror(r->u.file))
391 0 : r->error = errno;
392 3 : r->eof = 1;
393 3 : if (!n)
394 3 : return gpg_error (GPG_ERR_EOF);
395 : }
396 : }
397 0 : else if (r->type == READER_TYPE_CB)
398 : {
399 0 : if (r->eof)
400 0 : return gpg_error (GPG_ERR_EOF);
401 :
402 0 : if (r->u.cb.fnc (r->u.cb.value, buffer, length, nread))
403 : {
404 0 : *nread = 0;
405 0 : r->eof = 1;
406 0 : return gpg_error (GPG_ERR_EOF);
407 : }
408 0 : r->nread += *nread;
409 : }
410 : else
411 0 : return gpg_error (GPG_ERR_BUG);
412 :
413 974 : return 0;
414 : }
415 :
416 : gpg_error_t
417 1 : ksba_reader_unread (ksba_reader_t r, const void *buffer, size_t count)
418 : {
419 1 : if (!r || !buffer)
420 0 : return gpg_error (GPG_ERR_INV_VALUE);
421 1 : if (!count)
422 0 : return 0;
423 :
424 : /* Make sure that we do not push more bytes back than we have read.
425 : Otherwise r->nread won't have a clear semantic. */
426 1 : if (r->nread < count)
427 0 : return gpg_error (GPG_ERR_CONFLICT);
428 :
429 1 : if (!r->unread.buf)
430 : {
431 1 : r->unread.size = count + 100;
432 1 : r->unread.buf = xtrymalloc (r->unread.size);
433 1 : if (!r->unread.buf)
434 0 : return gpg_error (GPG_ERR_ENOMEM);
435 1 : r->unread.length = count;
436 1 : r->unread.readpos = 0;
437 1 : memcpy (r->unread.buf, buffer, count);
438 1 : r->nread -= count;
439 : }
440 0 : else if (r->unread.length + count < r->unread.size)
441 : {
442 0 : memcpy (r->unread.buf+r->unread.length, buffer, count);
443 0 : r->unread.length += count;
444 0 : r->nread -= count;
445 : }
446 : else
447 0 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* fixme: easy to do */
448 :
449 1 : return 0;
450 : }
|