e63fd520660cffcf9e37130175830ef79119c488
[gpgme.git] / gpgme / data.c
1 /* data.c
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include "syshdr.h"
29
30 #include "util.h"
31 #include "context.h"
32 #include "ops.h"
33
34 #define ALLOC_CHUNK 1024
35 #define my_isdigit(a)  ( (a) >='0' && (a) <= '9' )
36 #define my_isxdigit(a) ( my_isdigit((a))               \
37                          || ((a) >= 'A' && (a) <= 'F') \
38                          || ((a) >= 'f' && (a) <= 'f') )
39
40
41 /**
42  * gpgme_data_new:
43  * @r_dh: returns the new data object 
44  * 
45  * Create a new data object without any content. 
46  * 
47  * Return value: An error value or 0 on success
48  **/
49 GpgmeError
50 gpgme_data_new ( GpgmeData *r_dh )
51 {
52     GpgmeData dh;
53
54     if (!r_dh)
55         return mk_error (Invalid_Value);
56     *r_dh = NULL;
57     dh = xtrycalloc ( 1, sizeof *dh );
58     if (!dh)
59         return mk_error (Out_Of_Core);
60     dh->mode = GPGME_DATA_MODE_INOUT; 
61     *r_dh = dh;
62     return 0;
63 }
64
65
66 /**
67  * gpgme_data_new_from_mem:
68  * @r_dh:   Returns a new data object.
69  * @buffer: Initialize with this.
70  * @size: Size of the buffer
71  * @copy: Flag wether a copy of the buffer should be used.
72  * 
73  * Create a new data object and initialize with data
74  * from the memory.  A @copy with value %TRUE creates a copy of the
75  * memory, a value of %FALSE uses the original memory of @buffer and the
76  * caller has to make sure that this buffer is valid until gpgme_release_data()
77  * is called.
78  * 
79  * Return value: 
80  **/
81 GpgmeError
82 gpgme_data_new_from_mem ( GpgmeData *r_dh,
83                           const char *buffer, size_t size, int copy )
84 {
85     GpgmeData dh;
86     GpgmeError err;
87
88     if (!r_dh || !buffer)
89         return mk_error (Invalid_Value);
90     *r_dh = NULL;
91     err = gpgme_data_new ( &dh );
92     if (err)
93         return err;
94     dh->len = size;
95     if (copy) {
96         dh->private_buffer = xtrymalloc ( size );
97         if ( !dh->private_buffer ) {
98             gpgme_data_release (dh);
99             return mk_error (Out_Of_Core);
100         }
101         dh->private_len = size;
102         memcpy (dh->private_buffer, buffer, size );
103         dh->data = dh->private_buffer;
104         dh->writepos = size;
105     }
106     else {
107         dh->data = buffer;
108     }
109     dh->type = GPGME_DATA_TYPE_MEM;
110     
111     *r_dh = dh;
112     return 0;
113 }
114
115
116 GpgmeError
117 gpgme_data_new_with_read_cb ( GpgmeData *r_dh,
118                               int (*read_cb)(void*,char *,size_t,size_t*),
119                               void *read_cb_value )
120 {
121     GpgmeData dh;
122     GpgmeError err;
123
124     if (!r_dh || !read_cb)
125         return mk_error (Invalid_Value);
126     *r_dh = NULL;
127     err = gpgme_data_new ( &dh );
128     if (err)
129         return err;
130     dh->type = GPGME_DATA_TYPE_CB;
131     dh->mode = GPGME_DATA_MODE_OUT;
132     dh->read_cb = read_cb;
133     dh->read_cb_value = read_cb_value;
134     
135     *r_dh = dh;
136     return 0;
137 }
138
139 /**
140  * gpgme_data_new_from_file:
141  * @r_dh: returns the new data object
142  * @fname: filename
143  * @copy: Flag, whether the file should be copied.
144  * 
145  * Create a new data object and initialize it with the content of 
146  * the file @file.  If @copy is %True the file is immediately read in
147  * adn closed.  @copy of %False is not yet supportted.
148  * 
149  * Return value: An error code or 0 on success. If the error code is
150  * %GPGME_File_Error, the OS error code is held in %errno.
151  **/
152 GpgmeError
153 gpgme_data_new_from_file ( GpgmeData *r_dh, const char *fname, int copy )
154 {
155     GpgmeData dh;
156     GpgmeError err;
157     struct stat st;
158     FILE *fp;
159
160     if (!r_dh)
161         return mk_error (Invalid_Value);
162     *r_dh = NULL;
163     /* We only support copy for now - in future we might want to honor the 
164      * copy flag and just store a file pointer */
165     if (!copy)
166         return mk_error (Not_Implemented);
167     if (!fname)
168         return mk_error (Invalid_Value);
169
170     err = gpgme_data_new ( &dh );
171     if (err)
172         return err;
173
174     fp = fopen (fname, "rb");
175     if (!fp) {
176         int save_errno = errno;
177         gpgme_data_release (dh);
178         errno = save_errno;
179         return mk_error (File_Error);
180     }
181
182     if( fstat(fileno(fp), &st) ) {
183         int save_errno = errno;
184         fclose (fp);
185         gpgme_data_release (dh);
186         errno = save_errno;
187         return mk_error (File_Error);
188     }
189
190     /* We should check the length of the file and don't allow for to
191      * large files */
192     dh->private_buffer = xtrymalloc ( st.st_size );
193     if ( !dh->private_buffer ) {
194         fclose (fp);
195         gpgme_data_release (dh);
196         return mk_error (Out_Of_Core);
197     }
198     dh->private_len = st.st_size;
199
200     if ( fread ( dh->private_buffer, dh->private_len, 1, fp ) != 1 ) {
201         int save_errno = errno;
202         fclose (fp);
203         gpgme_data_release (dh);
204         errno = save_errno;
205         return mk_error (File_Error);
206     }
207
208     fclose (fp);
209
210     dh->len = dh->private_len;
211     dh->data = dh->private_buffer;
212     dh->writepos = dh->len;
213     dh->type = GPGME_DATA_TYPE_MEM;
214     
215     *r_dh = dh;
216     return 0;
217 }
218
219
220
221 /**
222  * gpgme_data_release:
223  * @dh: Data object 
224  * 
225  * Release the data object @dh.  @dh may be NULL in which case nothing
226  * happens.
227  **/
228 void
229 gpgme_data_release ( GpgmeData dh )
230 {
231     if (dh) {
232         xfree (dh->private_buffer); 
233         xfree (dh);
234     }
235 }
236
237 char *
238 _gpgme_data_release_and_return_string ( GpgmeData dh )
239 {
240     char *val = NULL;
241
242     if (dh) {
243         if ( _gpgme_data_append ( dh, "", 0 ) ) /* append EOS */
244             xfree (dh->private_buffer );
245         else {
246             val = dh->private_buffer;
247             if ( !val && dh->data ) {
248                 val = xtrymalloc ( dh->len );
249                 if ( val )
250                     memcpy ( val, dh->data, dh->len );
251             }
252         }
253         xfree (dh);
254     }
255     return val;
256 }
257
258 /**
259  * gpgme_data_release_and_get_mem:
260  * @dh: the data object
261  * @r_len: returns the length of the memory
262  * 
263  * Release the data object @dh and return its content and the length of
264  * that content.  The caller has to free this data.  @dh maybe NULL in
265  * which case NULL is returned.  I there is not enough memory for allocating
266  * the return value, NULL is returned and the object is released.
267  * 
268  * Return value: a pointer to an allocated buffer of length @r_len.
269  **/
270 char *
271 gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len )
272 {
273     char *val = NULL;
274
275     if (r_len)
276         *r_len = 0;
277     if (dh) {
278         size_t len = dh->len;
279         val = dh->private_buffer;
280         if ( !val && dh->data ) {
281             val = xtrymalloc ( len );
282             if ( val )
283                 memcpy ( val, dh->data, len );
284         }
285         xfree (dh);
286         if (val && r_len )
287             *r_len = len;
288     }
289     return val;
290 }
291
292
293 /**
294  * gpgme_data_get_type:
295  * @dh: the data object
296  * 
297  * Get the type of the data object.
298  * Data types are prefixed with %GPGME_DATA_TYPE_
299  * 
300  * Return value: the data type
301  **/
302 GpgmeDataType
303 gpgme_data_get_type ( GpgmeData dh )
304 {
305     if ( !dh || (!dh->data && !dh->read_cb))
306         return GPGME_DATA_TYPE_NONE;
307             
308     return dh->type;
309 }
310
311 void 
312 _gpgme_data_set_mode ( GpgmeData dh, GpgmeDataMode mode )
313 {
314     assert (dh);
315     dh->mode = mode;
316 }
317
318
319 GpgmeDataMode
320 _gpgme_data_get_mode ( GpgmeData dh )
321 {
322     assert (dh);
323     return dh->mode;
324 }
325
326 /**
327  * gpgme_data_rewind:
328  * @dh: the data object 
329  * 
330  * Prepare the data object in a way, that a gpgme_data_read() does start
331  * at the beginning of the data.  This has to be done for all types
332  * of data objects.
333  * 
334  * Return value: An error code or 0 on success
335  **/
336 GpgmeError
337 gpgme_data_rewind ( GpgmeData dh )
338 {
339     if ( !dh )
340         return mk_error (Invalid_Value);
341
342     if (dh->type == GPGME_DATA_TYPE_MEM ) {
343         dh->readpos = 0;
344     }
345     else if (dh->type == GPGME_DATA_TYPE_CB) {
346         dh->len = dh->readpos = 0;
347         dh->read_cb_eof = 0;
348         /* FIXME: do a special call to the read function to trigger a rewind
349            there */
350     }
351     else
352         return mk_error (General_Error);
353     return 0;
354 }
355
356 /**
357  * gpgme_data_read:
358  * @dh: the data object
359  * @buffer: A buffer 
360  * @length: The length of that bufer
361  * @nread: Returns the number of bytes actually read.
362  * 
363  * Copy data from the current read position (which may be set by
364  * gpgme_data_rewind()) to the supplied @buffer, max. @length bytes
365  * are copied and the actual number of bytes are returned in @nread.
366  * If there are no more bytes available %GPGME_EOF is returned and @nread
367  * is set to 0.
368  * 
369  * Return value: An errorcode or 0 on success, EOF is indcated by the
370  * error code GPGME_EOF.
371  **/
372 GpgmeError
373 gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
374 {
375     size_t nbytes;
376
377     if ( !dh )
378         return mk_error (Invalid_Value);
379     if (dh->type == GPGME_DATA_TYPE_MEM ) {
380         nbytes = dh->len - dh->readpos;
381         if ( !nbytes ) {
382             *nread = 0;
383             return mk_error(EOF);
384         }
385         if (nbytes > length)
386             nbytes = length;
387         memcpy ( buffer, dh->data + dh->readpos, nbytes );
388         *nread = nbytes;
389         dh->readpos += nbytes;
390     }
391     else if (dh->type == GPGME_DATA_TYPE_CB) {
392         nbytes = dh->len - dh->readpos;
393         if ( nbytes ) {
394             /* we have unread data - return this */
395             if (nbytes > length)
396                 nbytes = length;
397             memcpy ( buffer, dh->data + dh->readpos, nbytes );
398             *nread = nbytes;
399             dh->readpos += nbytes;
400         }
401         else { /* get the data from the callback */
402             if (!dh->read_cb || dh->read_cb_eof) { 
403                 *nread = 0;
404                 return mk_error (EOF);
405             }
406             if (dh->read_cb (dh->read_cb_value, buffer, length, nread )) {
407                 *nread = 0;
408                 dh->read_cb_eof = 1;
409                 return mk_error (EOF);
410             }
411         }
412     }
413     else
414         return mk_error (General_Error);
415     return 0;
416
417
418 GpgmeError
419 _gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length )
420 {
421    if ( !dh )
422         return mk_error (Invalid_Value);
423
424    if (dh->type == GPGME_DATA_TYPE_MEM ) {
425        /* check that we don't unread more than we have yet read */
426        if ( dh->readpos < length )
427            return mk_error (Invalid_Value);
428        /* No need to use the buffer for this data type */
429        dh->readpos -= length;
430    }
431    else {
432        return mk_error (General_Error);
433    }
434
435    return 0;
436 }
437
438
439 /* 
440  * This function does make sense when we know that it contains no nil chars.
441  */
442 char *
443 _gpgme_data_get_as_string ( GpgmeData dh )
444 {
445     char *val = NULL;
446
447     if (dh) {
448         val = xtrymalloc ( dh->len+1 );
449         if ( val ) {
450             memcpy ( val, dh->data, dh->len );
451             val[dh->len] = 0;
452         }
453     }
454     return val;
455 }
456
457
458
459 GpgmeError
460 _gpgme_data_append ( GpgmeData dh, const char *buffer, size_t length )
461 {
462     assert (dh);
463
464     if ( dh->type == GPGME_DATA_TYPE_NONE ) {
465         /* convert it to a mem data type */
466         assert (!dh->private_buffer);
467         dh->type = GPGME_DATA_TYPE_MEM;
468         dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length;
469         dh->private_buffer = xtrymalloc ( dh->private_len );
470         if (!dh->private_buffer) {
471             dh->private_len = 0;
472             return mk_error (Out_Of_Core);
473         }
474         dh->writepos = 0;
475         dh->data = dh->private_buffer;
476     }
477     else if ( dh->type != GPGME_DATA_TYPE_MEM ) 
478         return mk_error (Invalid_Type);
479     
480     if ( dh->mode != GPGME_DATA_MODE_INOUT 
481          && dh->mode != GPGME_DATA_MODE_IN  )
482         return mk_error (Invalid_Mode);
483
484     if ( !dh->private_buffer ) {
485         /* we have to copy it now */
486         assert (dh->data);
487         dh->private_len = dh->len+length;
488         if (dh->private_len < ALLOC_CHUNK)
489             dh->private_len = ALLOC_CHUNK;
490         dh->private_buffer = xtrymalloc ( dh->private_len );
491         if (!dh->private_buffer) {
492             dh->private_len = 0;
493             return mk_error (Out_Of_Core);
494         }
495         memcpy ( dh->private_buffer, dh->data, dh->len );
496         dh->writepos = dh->len;
497         dh->data = dh->private_buffer;
498     }
499
500     /* allocate more memory if needed */
501     if ( dh->writepos + length > dh->private_len ) {
502         char *p;
503         size_t newlen = dh->private_len
504                         + (dh->len < ALLOC_CHUNK? ALLOC_CHUNK : length);
505         p = xtryrealloc ( dh->private_buffer, newlen );
506         if ( !p ) 
507             return mk_error (Out_Of_Core);
508         dh->private_buffer = p;
509         dh->private_len = newlen;
510         dh->data = dh->private_buffer;
511         assert ( !(dh->writepos + length > dh->private_len) );      
512     }
513
514     memcpy ( dh->private_buffer + dh->writepos, buffer, length );
515     dh->writepos += length;
516     dh->len += length;
517
518     return 0;
519 }
520
521 GpgmeError
522 _gpgme_data_append_string ( GpgmeData dh, const char *s )
523 {
524     return _gpgme_data_append ( dh, s, s? strlen(s):0 );
525 }
526
527
528 GpgmeError
529 _gpgme_data_append_for_xml ( GpgmeData dh,
530                              const char *buffer, size_t len )
531 {
532     const char *text, *s;
533     size_t n;
534     int rc = 0; 
535        
536     if ( !dh || !buffer )
537         return mk_error (Invalid_Value);
538
539     do {
540         for (text=NULL, s=buffer, n=len; n && !text; s++, n-- ) {
541             if ( *s == '<' ) 
542                 text = "&lt;";
543             else if ( *s == '>' ) 
544                 text = "&gt;";  /* not sure whether this is really needed */
545             else if ( *s == '&' ) 
546                 text = "&amp;";
547             else if ( !*s )
548                 text = "&#00;";
549         }
550         if (text) {
551             s--; n++;
552         }
553         if (s != buffer) 
554             rc = _gpgme_data_append ( dh, buffer, s-buffer );
555         if ( !rc && text) {
556             rc = _gpgme_data_append_string ( dh, text );
557             s++; n--;
558         }
559         buffer = s;
560         len = n;
561     } while ( !rc && len );
562     return rc;
563 }
564
565
566 /*
567  * Append a string to DATA and convert it so that the result will be 
568  * valid XML. 
569  */
570 GpgmeError
571 _gpgme_data_append_string_for_xml ( GpgmeData dh, const char *string )
572 {
573     return _gpgme_data_append_for_xml ( dh, string, strlen (string) );
574 }
575
576
577 static int
578 hextobyte( const byte *s )
579 {
580     int c;
581
582     if( *s >= '0' && *s <= '9' )
583         c = 16 * (*s - '0');
584     else if( *s >= 'A' && *s <= 'F' )
585         c = 16 * (10 + *s - 'A');
586     else if( *s >= 'a' && *s <= 'f' )
587         c = 16 * (10 + *s - 'a');
588     else
589         return -1;
590     s++;
591     if( *s >= '0' && *s <= '9' )
592         c += *s - '0';
593     else if( *s >= 'A' && *s <= 'F' )
594         c += 10 + *s - 'A';
595     else if( *s >= 'a' && *s <= 'f' )
596         c += 10 + *s - 'a';
597     else
598         return -1;
599     return c;
600 }
601
602
603
604
605 /* 
606  * Append a string with percent style (%XX) escape characters as XML
607  */
608 GpgmeError
609 _gpgme_data_append_percentstring_for_xml ( GpgmeData dh, const char *string )
610 {
611     const byte *s;
612     byte *buf, *d;
613     int val;
614     GpgmeError err;
615
616     d = buf = xtrymalloc ( strlen (string) );
617     for (s=string; *s; s++ ) {
618         if ( *s == '%' && (val=hextobyte (s+1)) != -1 ) {
619             *d++ = val;
620             s += 2;
621         }
622         else
623             *d++ = *s;
624     }
625
626     err = _gpgme_data_append_for_xml ( dh, buf, d - buf );
627     xfree (buf);
628     return err;
629 }
630
631
632
633
634
635
636