Line data Source code
1 : /* writer.c - provides the Writer 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 "writer.h"
41 : #include "asn1-func.h"
42 : #include "ber-help.h"
43 :
44 : /**
45 : * ksba_writer_new:
46 : *
47 : * Create a new but uninitialized ksba_writer_t Object. Using this
48 : * write object in unitialized state does always return an error.
49 : *
50 : * Return value: ksba_writer_t object or an error code.
51 : **/
52 : gpg_error_t
53 21 : ksba_writer_new (ksba_writer_t *r_w)
54 : {
55 21 : *r_w = xtrycalloc (1, sizeof **r_w);
56 21 : if (!*r_w)
57 0 : return gpg_error_from_errno (errno);
58 :
59 21 : return 0;
60 : }
61 :
62 :
63 : /**
64 : * ksba_writer_release:
65 : * @w: Writer Object (or NULL)
66 : *
67 : * Release this object
68 : **/
69 : void
70 21 : ksba_writer_release (ksba_writer_t w)
71 : {
72 21 : if (!w)
73 21 : return;
74 21 : if (w->notify_cb)
75 : {
76 0 : void (*notify_fnc)(void*,ksba_writer_t) = w->notify_cb;
77 :
78 0 : w->notify_cb = NULL;
79 0 : notify_fnc (w->notify_cb_value, w);
80 : }
81 21 : if (w->type == WRITER_TYPE_MEM)
82 10 : xfree (w->u.mem.buffer);
83 21 : xfree (w);
84 : }
85 :
86 :
87 : /* Set NOTIFY as function to be called by ksba_reader_release before
88 : resources are actually deallocated. NOTIFY_VALUE is passed to the
89 : called function as its first argument. Note that only the last
90 : registered function will be called; passing NULL for NOTIFY removes
91 : the notification. */
92 : gpg_error_t
93 0 : ksba_writer_set_release_notify (ksba_writer_t w,
94 : void (*notify)(void*,ksba_writer_t),
95 : void *notify_value)
96 : {
97 0 : if (!w)
98 0 : return gpg_error (GPG_ERR_INV_VALUE);
99 0 : w->notify_cb = notify;
100 0 : w->notify_cb_value = notify_value;
101 0 : return 0;
102 : }
103 :
104 :
105 : int
106 0 : ksba_writer_error (ksba_writer_t w)
107 : {
108 0 : return w? gpg_error_from_errno (w->error) : gpg_error (GPG_ERR_INV_VALUE);
109 : }
110 :
111 : unsigned long
112 0 : ksba_writer_tell (ksba_writer_t w)
113 : {
114 0 : return w? w->nwritten : 0;
115 : }
116 :
117 :
118 : /**
119 : * ksba_writer_set_fd:
120 : * @w: Writer object
121 : * @fd: file descriptor
122 : *
123 : * Initialize the Writer object with a file descriptor, so that write
124 : * operations on this object are excuted on this file descriptor.
125 : *
126 : * Return value:
127 : **/
128 : gpg_error_t
129 0 : ksba_writer_set_fd (ksba_writer_t w, int fd)
130 : {
131 0 : if (!w || fd == -1)
132 0 : return gpg_error (GPG_ERR_INV_VALUE);
133 0 : if (w->type)
134 0 : return gpg_error (GPG_ERR_CONFLICT);
135 :
136 0 : w->error = 0;
137 0 : w->type = WRITER_TYPE_FD;
138 0 : w->u.fd = fd;
139 :
140 0 : return 0;
141 : }
142 :
143 : /**
144 : * ksba_writer_set_file:
145 : * @w: Writer object
146 : * @fp: file pointer
147 : *
148 : * Initialize the Writer object with a stdio file pointer, so that write
149 : * operations on this object are excuted on this stream
150 : *
151 : * Return value:
152 : **/
153 : gpg_error_t
154 0 : ksba_writer_set_file (ksba_writer_t w, FILE *fp)
155 : {
156 0 : if (!w || !fp)
157 0 : return gpg_error (GPG_ERR_INV_VALUE);
158 0 : if (w->type)
159 0 : return gpg_error (GPG_ERR_CONFLICT);
160 :
161 0 : w->error = 0;
162 0 : w->type = WRITER_TYPE_FILE;
163 0 : w->u.file = fp;
164 0 : return 0;
165 : }
166 :
167 :
168 :
169 : /**
170 : * ksba_writer_set_cb:
171 : * @w: Writer object
172 : * @cb: Callback function
173 : * @cb_value: Value passed to the callback function
174 : *
175 : * Initialize the writer object with a callback function.
176 : * This callback function is defined as:
177 : * <literal>
178 : * typedef int (*cb) (void *cb_value,
179 : * const void *buffer, size_t count);
180 : * </literal>
181 : *
182 : * The callback is expected to process all @count bytes from @buffer
183 : * @count should not be 0 and @buffer should not be %NULL
184 : * The callback should return 0 on success or an %KSBA_xxx error code.
185 : *
186 : * Return value: 0 on success or an error code
187 : **/
188 : gpg_error_t
189 0 : ksba_writer_set_cb (ksba_writer_t w,
190 : int (*cb)(void*,const void *,size_t), void *cb_value )
191 : {
192 0 : if (!w || !cb)
193 0 : return gpg_error (GPG_ERR_INV_VALUE);
194 0 : if (w->type)
195 0 : return gpg_error (GPG_ERR_CONFLICT);
196 :
197 0 : w->error = 0;
198 0 : w->type = WRITER_TYPE_CB;
199 0 : w->u.cb.fnc = cb;
200 0 : w->u.cb.value = cb_value;
201 :
202 0 : return 0;
203 : }
204 :
205 :
206 : gpg_error_t
207 32 : ksba_writer_set_mem (ksba_writer_t w, size_t initial_size)
208 : {
209 32 : if (!w)
210 0 : return gpg_error (GPG_ERR_INV_VALUE);
211 32 : if (w->type == WRITER_TYPE_MEM)
212 : ; /* Reuse the buffer (we ignore the initial size)*/
213 : else
214 : {
215 32 : if (w->type)
216 0 : return gpg_error (GPG_ERR_CONFLICT);
217 :
218 32 : if (!initial_size)
219 0 : initial_size = 1024;
220 :
221 32 : w->u.mem.buffer = xtrymalloc (initial_size);
222 32 : if (!w->u.mem.buffer)
223 0 : return gpg_error (GPG_ERR_ENOMEM);
224 32 : w->u.mem.size = initial_size;
225 32 : w->type = WRITER_TYPE_MEM;
226 : }
227 32 : w->error = 0;
228 32 : w->nwritten = 0;
229 :
230 32 : return 0;
231 : }
232 :
233 : /* Return the pointer to the memory and the size of it. This pointer
234 : is valid as long as the writer object is valid and no write
235 : operations takes place (because they might reallocate the buffer).
236 : if NBYTES is not NULL, it will receive the number of bytes in this
237 : buffer which is the same value ksba_writer_tell() returns.
238 :
239 : In case of an error NULL is returned.
240 : */
241 : const void *
242 0 : ksba_writer_get_mem (ksba_writer_t w, size_t *nbytes)
243 : {
244 0 : if (!w || w->type != WRITER_TYPE_MEM || w->error)
245 0 : return NULL;
246 0 : if (nbytes)
247 0 : *nbytes = w->nwritten;
248 0 : return w->u.mem.buffer;
249 : }
250 :
251 : /* Return the the memory and the size of it. The writer object is set
252 : back into the uninitalized state; i.e. one of the
253 : ksab_writer_set_xxx () must be used before all other operations.
254 : if NBYTES is not NULL, it will receive the number of bytes in this
255 : buffer which is the same value ksba_writer_tell() returns.
256 :
257 : In case of an error NULL is returned. */
258 : void *
259 22 : ksba_writer_snatch_mem (ksba_writer_t w, size_t *nbytes)
260 : {
261 : void *p;
262 :
263 22 : if (!w || w->type != WRITER_TYPE_MEM || w->error)
264 0 : return NULL;
265 22 : if (nbytes)
266 22 : *nbytes = w->nwritten;
267 22 : p = w->u.mem.buffer;
268 22 : w->u.mem.buffer = NULL;
269 22 : w->type = 0;
270 22 : w->nwritten = 0;
271 22 : return p;
272 : }
273 :
274 :
275 :
276 : gpg_error_t
277 0 : ksba_writer_set_filter (ksba_writer_t w,
278 : gpg_error_t (*filter)(void*,
279 : const void *,size_t, size_t *,
280 : void *, size_t, size_t *),
281 : void *filter_arg)
282 : {
283 0 : if (!w)
284 0 : return gpg_error (GPG_ERR_INV_VALUE);
285 :
286 0 : w->filter = filter;
287 0 : w->filter_arg = filter_arg;
288 0 : return 0;
289 : }
290 :
291 :
292 :
293 :
294 : static gpg_error_t
295 281 : do_writer_write (ksba_writer_t w, const void *buffer, size_t length)
296 : {
297 281 : if (!w->type)
298 : {
299 0 : w->error = EINVAL;
300 0 : return gpg_error_from_errno (w->error);
301 : }
302 281 : else if (w->type == WRITER_TYPE_MEM)
303 : {
304 281 : if (w->error == ENOMEM)
305 0 : return gpg_error (GPG_ERR_ENOMEM); /* it does not make sense to proceed then */
306 :
307 281 : if (w->nwritten + length > w->u.mem.size)
308 : {
309 0 : size_t newsize = w->nwritten + length;
310 : char *p;
311 :
312 0 : newsize = ((newsize + 4095)/4096)*4096;
313 0 : if (newsize < 16384)
314 0 : newsize += 4096;
315 : else
316 0 : newsize += 16384;
317 :
318 0 : p = xtryrealloc (w->u.mem.buffer, newsize);
319 0 : if (!p)
320 : {
321 : /* Keep an error flag so that the user does not need to
322 : check the return code of a write but instead use
323 : ksba_writer_error() to check for it or even figure
324 : this state out when using ksba_writer_get_mem() */
325 0 : w->error = ENOMEM;
326 0 : return gpg_error (GPG_ERR_ENOMEM);
327 : }
328 0 : w->u.mem.buffer = p;
329 0 : w->u.mem.size = newsize;
330 : /* Better check again in case of an overwrap. */
331 0 : if (w->nwritten + length > w->u.mem.size)
332 0 : return gpg_error (GPG_ERR_ENOMEM);
333 : }
334 281 : memcpy (w->u.mem.buffer + w->nwritten, buffer, length);
335 281 : w->nwritten += length;
336 : }
337 0 : else if (w->type == WRITER_TYPE_FILE)
338 : {
339 0 : if (!length)
340 0 : return 0;
341 :
342 0 : if ( fwrite (buffer, length, 1, w->u.file) == 1)
343 : {
344 0 : w->nwritten += length;
345 : }
346 : else
347 : {
348 0 : w->error = errno;
349 0 : return gpg_error_from_errno (errno);
350 : }
351 : }
352 0 : else if (w->type == WRITER_TYPE_CB)
353 : {
354 0 : int err = w->u.cb.fnc (w->u.cb.value, buffer, length);
355 0 : if (err)
356 0 : return err;
357 0 : w->nwritten += length;
358 : }
359 : else
360 0 : return gpg_error (GPG_ERR_BUG);
361 :
362 281 : return 0;
363 : }
364 :
365 : /**
366 : * ksba_writer_write:
367 : * @w: Writer object
368 : * @buffer: A buffer with the data to be written
369 : * @length: The length of this buffer
370 : *
371 : * Write @length bytes from @buffer.
372 : *
373 : * Return value: 0 on success or an error code
374 : **/
375 : gpg_error_t
376 281 : ksba_writer_write (ksba_writer_t w, const void *buffer, size_t length)
377 : {
378 281 : gpg_error_t err=0;
379 :
380 281 : if (!w)
381 0 : return gpg_error (GPG_ERR_INV_VALUE);
382 :
383 281 : if (!buffer)
384 0 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
385 :
386 281 : if (w->filter)
387 : {
388 : char outbuf[4096];
389 : size_t nin, nout;
390 0 : const char *p = buffer;
391 :
392 0 : while (length)
393 : {
394 0 : err = w->filter (w->filter_arg, p, length, &nin,
395 : outbuf, sizeof (outbuf), &nout);
396 0 : if (err)
397 0 : break;
398 0 : if (nin > length || nout > sizeof (outbuf))
399 0 : return gpg_error (GPG_ERR_BUG); /* tsss, someone else made an error */
400 0 : err = do_writer_write (w, outbuf, nout);
401 0 : if (err)
402 0 : break;
403 0 : length -= nin;
404 0 : p += nin;
405 : }
406 : }
407 : else
408 : {
409 281 : err = do_writer_write (w, buffer, length);
410 : }
411 :
412 281 : return err;
413 : }
414 :
415 : /* Write LENGTH bytes of BUFFER to W while encoding it as an BER
416 : encoded octet string. With FLUSH set to 1 the octet stream will be
417 : terminated. If the entire octet string is available in BUFFER it
418 : is a good idea to set FLUSH to 1 so that the function does not need
419 : to encode the string partially. */
420 : gpg_error_t
421 0 : ksba_writer_write_octet_string (ksba_writer_t w,
422 : const void *buffer, size_t length, int flush)
423 : {
424 0 : gpg_error_t err = 0;
425 :
426 0 : if (!w)
427 0 : return gpg_error (GPG_ERR_INV_VALUE);
428 :
429 0 : if (buffer && length)
430 : {
431 0 : if (!w->ndef_is_open && !flush)
432 : {
433 0 : err = _ksba_ber_write_tl (w, TYPE_OCTET_STRING,
434 : CLASS_UNIVERSAL, 1, 0);
435 0 : if (err)
436 0 : return err;
437 0 : w->ndef_is_open = 1;
438 : }
439 :
440 0 : err = _ksba_ber_write_tl (w, TYPE_OCTET_STRING,
441 : CLASS_UNIVERSAL, 0, length);
442 0 : if (!err)
443 0 : err = ksba_writer_write (w, buffer, length);
444 : }
445 :
446 0 : if (!err && flush && w->ndef_is_open) /* write an end tag */
447 0 : err = _ksba_ber_write_tl (w, 0, 0, 0, 0);
448 :
449 0 : if (flush) /* Reset it even in case of an error. */
450 0 : w->ndef_is_open = 1;
451 :
452 0 : return err;
453 : }
|