Add 2 missing files and other changes
[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 GpgmeError
221 gpgme_data_new_from_filepart ( GpgmeData *r_dh, const char *fname, FILE *fp,
222                                off_t offset, off_t length )
223 {
224     GpgmeData dh;
225     GpgmeError err;
226
227     if (!r_dh)
228         return mk_error (Invalid_Value);
229     *r_dh = NULL;
230     if ( fname && fp ) /* these are mutual exclusive */
231         return mk_error (Invalid_Value);
232     if (!fname && !fp)
233         return mk_error (Invalid_Value);
234     if (!length)
235         return mk_error (Invalid_Value);
236
237     err = gpgme_data_new ( &dh );
238     if (err)
239         return err;
240
241     if (!fp) {
242         fp = fopen (fname, "rb");
243         if (!fp) {
244             int save_errno = errno;
245             gpgme_data_release (dh);
246             errno = save_errno;
247             return mk_error (File_Error);
248         }
249     }
250
251     if ( fseek ( fp, (long)offset, SEEK_SET) ) {
252         int save_errno = errno;
253         if (fname)
254             fclose (fp);
255         gpgme_data_release (dh);
256         errno = save_errno;
257         return mk_error (File_Error);
258     }
259
260
261     dh->private_buffer = xtrymalloc ( length );
262     if ( !dh->private_buffer ) {
263         if (fname)
264             fclose (fp);
265         gpgme_data_release (dh);
266         return mk_error (Out_Of_Core);
267     }
268     dh->private_len = length;
269
270     if ( fread ( dh->private_buffer, dh->private_len, 1, fp ) != 1 ) {
271         int save_errno = errno;
272         if (fname)
273             fclose (fp);
274         gpgme_data_release (dh);
275         errno = save_errno;
276         return mk_error (File_Error);
277     }
278
279     if (fname)
280         fclose (fp);
281
282     dh->len = dh->private_len;
283     dh->data = dh->private_buffer;
284     dh->writepos = dh->len;
285     dh->type = GPGME_DATA_TYPE_MEM;
286     
287     *r_dh = dh;
288     return 0;
289 }
290
291
292 /**
293  * gpgme_data_release:
294  * @dh: Data object 
295  * 
296  * Release the data object @dh.  @dh may be NULL in which case nothing
297  * happens.
298  **/
299 void
300 gpgme_data_release ( GpgmeData dh )
301 {
302     if (dh) {
303         xfree (dh->private_buffer); 
304         xfree (dh);
305     }
306 }
307
308 char *
309 _gpgme_data_release_and_return_string ( GpgmeData dh )
310 {
311     char *val = NULL;
312
313     if (dh) {
314         if ( _gpgme_data_append ( dh, "", 0 ) ) /* append EOS */
315             xfree (dh->private_buffer );
316         else {
317             val = dh->private_buffer;
318             if ( !val && dh->data ) {
319                 val = xtrymalloc ( dh->len );
320                 if ( val )
321                     memcpy ( val, dh->data, dh->len );
322             }
323         }
324         xfree (dh);
325     }
326     return val;
327 }
328
329 /**
330  * gpgme_data_release_and_get_mem:
331  * @dh: the data object
332  * @r_len: returns the length of the memory
333  * 
334  * Release the data object @dh and return its content and the length of
335  * that content.  The caller has to free this data.  @dh maybe NULL in
336  * which case NULL is returned.  I there is not enough memory for allocating
337  * the return value, NULL is returned and the object is released.
338  * 
339  * Return value: a pointer to an allocated buffer of length @r_len.
340  **/
341 char *
342 gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len )
343 {
344     char *val = NULL;
345
346     if (r_len)
347         *r_len = 0;
348     if (dh) {
349         size_t len = dh->len;
350         val = dh->private_buffer;
351         if ( !val && dh->data ) {
352             val = xtrymalloc ( len );
353             if ( val )
354                 memcpy ( val, dh->data, len );
355         }
356         xfree (dh);
357         if (val && r_len )
358             *r_len = len;
359     }
360     return val;
361 }
362
363
364 /**
365  * gpgme_data_get_type:
366  * @dh: the data object
367  * 
368  * Get the type of the data object.
369  * Data types are prefixed with %GPGME_DATA_TYPE_
370  * 
371  * Return value: the data type
372  **/
373 GpgmeDataType
374 gpgme_data_get_type ( GpgmeData dh )
375 {
376     if ( !dh || (!dh->data && !dh->read_cb))
377         return GPGME_DATA_TYPE_NONE;
378             
379     return dh->type;
380 }
381
382 void 
383 _gpgme_data_set_mode ( GpgmeData dh, GpgmeDataMode mode )
384 {
385     assert (dh);
386     dh->mode = mode;
387 }
388
389
390 GpgmeDataMode
391 _gpgme_data_get_mode ( GpgmeData dh )
392 {
393     assert (dh);
394     return dh->mode;
395 }
396
397 /**
398  * gpgme_data_rewind:
399  * @dh: the data object 
400  * 
401  * Prepare the data object in a way, that a gpgme_data_read() does start
402  * at the beginning of the data.  This has to be done for all types
403  * of data objects.
404  * 
405  * Return value: An error code or 0 on success
406  **/
407 GpgmeError
408 gpgme_data_rewind ( GpgmeData dh )
409 {
410     if ( !dh )
411         return mk_error (Invalid_Value);
412
413     if (dh->type == GPGME_DATA_TYPE_MEM ) {
414         dh->readpos = 0;
415     }
416     else if (dh->type == GPGME_DATA_TYPE_CB) {
417         dh->len = dh->readpos = 0;
418         dh->read_cb_eof = 0;
419         /* FIXME: do a special call to the read function to trigger a rewind
420            there */
421     }
422     else
423         return mk_error (General_Error);
424     return 0;
425 }
426
427 /**
428  * gpgme_data_read:
429  * @dh: the data object
430  * @buffer: A buffer 
431  * @length: The length of that bufer
432  * @nread: Returns the number of bytes actually read.
433  * 
434  * Copy data from the current read position (which may be set by
435  * gpgme_data_rewind()) to the supplied @buffer, max. @length bytes
436  * are copied and the actual number of bytes are returned in @nread.
437  * If there are no more bytes available %GPGME_EOF is returned and @nread
438  * is set to 0.
439  * 
440  * Return value: An errorcode or 0 on success, EOF is indcated by the
441  * error code GPGME_EOF.
442  **/
443 GpgmeError
444 gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
445 {
446     size_t nbytes;
447
448     if ( !dh )
449         return mk_error (Invalid_Value);
450     if (dh->type == GPGME_DATA_TYPE_MEM ) {
451         nbytes = dh->len - dh->readpos;
452         if ( !nbytes ) {
453             *nread = 0;
454             return mk_error(EOF);
455         }
456         if (nbytes > length)
457             nbytes = length;
458         memcpy ( buffer, dh->data + dh->readpos, nbytes );
459         *nread = nbytes;
460         dh->readpos += nbytes;
461     }
462     else if (dh->type == GPGME_DATA_TYPE_CB) {
463         nbytes = dh->len - dh->readpos;
464         if ( nbytes ) {
465             /* we have unread data - return this */
466             if (nbytes > length)
467                 nbytes = length;
468             memcpy ( buffer, dh->data + dh->readpos, nbytes );
469             *nread = nbytes;
470             dh->readpos += nbytes;
471         }
472         else { /* get the data from the callback */
473             if (!dh->read_cb || dh->read_cb_eof) { 
474                 *nread = 0;
475                 return mk_error (EOF);
476             }
477             if (dh->read_cb (dh->read_cb_value, buffer, length, nread )) {
478                 *nread = 0;
479                 dh->read_cb_eof = 1;
480                 return mk_error (EOF);
481             }
482         }
483     }
484     else
485         return mk_error (General_Error);
486     return 0;
487
488
489 GpgmeError
490 _gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length )
491 {
492    if ( !dh )
493         return mk_error (Invalid_Value);
494
495    if (dh->type == GPGME_DATA_TYPE_MEM ) {
496        /* check that we don't unread more than we have yet read */
497        if ( dh->readpos < length )
498            return mk_error (Invalid_Value);
499        /* No need to use the buffer for this data type */
500        dh->readpos -= length;
501    }
502    else {
503        return mk_error (General_Error);
504    }
505
506    return 0;
507 }
508
509
510 /* 
511  * This function does make sense when we know that it contains no nil chars.
512  */
513 char *
514 _gpgme_data_get_as_string ( GpgmeData dh )
515 {
516     char *val = NULL;
517
518     if (dh) {
519         val = xtrymalloc ( dh->len+1 );
520         if ( val ) {
521             memcpy ( val, dh->data, dh->len );
522             val[dh->len] = 0;
523         }
524     }
525     return val;
526 }
527
528
529 /**
530  * gpgme_data_write:
531  * @dh: the context
532  * @buffer: data to be written to the data object
533  * @length: length o this data
534  * 
535  * Write the content of @buffer to the data object @dh at the current write
536  * position. 
537  * 
538  * Return value: 0 on succress or an errorcode
539  **/
540 GpgmeError
541 gpgme_data_write ( GpgmeData dh, const char *buffer, size_t length )
542 {
543     if (!dh || !buffer)
544         return mk_error (Invalid_Value);
545       
546     return _gpgme_data_append (dh, buffer, length );
547 }
548
549
550 GpgmeError
551 _gpgme_data_append ( GpgmeData dh, const char *buffer, size_t length )
552 {
553     assert (dh);
554
555     if ( dh->type == GPGME_DATA_TYPE_NONE ) {
556         /* convert it to a mem data type */
557         assert (!dh->private_buffer);
558         dh->type = GPGME_DATA_TYPE_MEM;
559         dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length;
560         dh->private_buffer = xtrymalloc ( dh->private_len );
561         if (!dh->private_buffer) {
562             dh->private_len = 0;
563             return mk_error (Out_Of_Core);
564         }
565         dh->writepos = 0;
566         dh->data = dh->private_buffer;
567     }
568     else if ( dh->type != GPGME_DATA_TYPE_MEM ) 
569         return mk_error (Invalid_Type);
570     
571     if ( dh->mode != GPGME_DATA_MODE_INOUT 
572          && dh->mode != GPGME_DATA_MODE_IN  )
573         return mk_error (Invalid_Mode);
574
575     if ( !dh->private_buffer ) {
576         /* we have to copy it now */
577         assert (dh->data);
578         dh->private_len = dh->len+length;
579         if (dh->private_len < ALLOC_CHUNK)
580             dh->private_len = ALLOC_CHUNK;
581         dh->private_buffer = xtrymalloc ( dh->private_len );
582         if (!dh->private_buffer) {
583             dh->private_len = 0;
584             return mk_error (Out_Of_Core);
585         }
586         memcpy ( dh->private_buffer, dh->data, dh->len );
587         dh->writepos = dh->len;
588         dh->data = dh->private_buffer;
589     }
590
591     /* allocate more memory if needed */
592     if ( dh->writepos + length > dh->private_len ) {
593         char *p;
594         size_t newlen = dh->private_len
595                         + (dh->len < ALLOC_CHUNK? ALLOC_CHUNK : length);
596         p = xtryrealloc ( dh->private_buffer, newlen );
597         if ( !p ) 
598             return mk_error (Out_Of_Core);
599         dh->private_buffer = p;
600         dh->private_len = newlen;
601         dh->data = dh->private_buffer;
602         assert ( !(dh->writepos + length > dh->private_len) );      
603     }
604
605     memcpy ( dh->private_buffer + dh->writepos, buffer, length );
606     dh->writepos += length;
607     dh->len += length;
608
609     return 0;
610 }
611
612 GpgmeError
613 _gpgme_data_append_string ( GpgmeData dh, const char *s )
614 {
615     return _gpgme_data_append ( dh, s, s? strlen(s):0 );
616 }
617
618
619 GpgmeError
620 _gpgme_data_append_for_xml ( GpgmeData dh,
621                              const char *buffer, size_t len )
622 {
623     const char *text, *s;
624     size_t n;
625     int rc = 0; 
626        
627     if ( !dh || !buffer )
628         return mk_error (Invalid_Value);
629
630     do {
631         for (text=NULL, s=buffer, n=len; n && !text; s++, n-- ) {
632             if ( *s == '<' ) 
633                 text = "&lt;";
634             else if ( *s == '>' ) 
635                 text = "&gt;";  /* not sure whether this is really needed */
636             else if ( *s == '&' ) 
637                 text = "&amp;";
638             else if ( !*s )
639                 text = "&#00;";
640         }
641         if (text) {
642             s--; n++;
643         }
644         if (s != buffer) 
645             rc = _gpgme_data_append ( dh, buffer, s-buffer );
646         if ( !rc && text) {
647             rc = _gpgme_data_append_string ( dh, text );
648             s++; n--;
649         }
650         buffer = s;
651         len = n;
652     } while ( !rc && len );
653     return rc;
654 }
655
656
657 /*
658  * Append a string to DATA and convert it so that the result will be 
659  * valid XML. 
660  */
661 GpgmeError
662 _gpgme_data_append_string_for_xml ( GpgmeData dh, const char *string )
663 {
664     return _gpgme_data_append_for_xml ( dh, string, strlen (string) );
665 }
666
667
668 static int
669 hextobyte( const byte *s )
670 {
671     int c;
672
673     if( *s >= '0' && *s <= '9' )
674         c = 16 * (*s - '0');
675     else if( *s >= 'A' && *s <= 'F' )
676         c = 16 * (10 + *s - 'A');
677     else if( *s >= 'a' && *s <= 'f' )
678         c = 16 * (10 + *s - 'a');
679     else
680         return -1;
681     s++;
682     if( *s >= '0' && *s <= '9' )
683         c += *s - '0';
684     else if( *s >= 'A' && *s <= 'F' )
685         c += 10 + *s - 'A';
686     else if( *s >= 'a' && *s <= 'f' )
687         c += 10 + *s - 'a';
688     else
689         return -1;
690     return c;
691 }
692
693
694
695
696 /* 
697  * Append a string with percent style (%XX) escape characters as XML
698  */
699 GpgmeError
700 _gpgme_data_append_percentstring_for_xml ( GpgmeData dh, const char *string )
701 {
702     const byte *s;
703     byte *buf, *d;
704     int val;
705     GpgmeError err;
706
707     d = buf = xtrymalloc ( strlen (string) );
708     for (s=string; *s; s++ ) {
709         if ( *s == '%' && (val=hextobyte (s+1)) != -1 ) {
710             *d++ = val;
711             s += 2;
712         }
713         else
714             *d++ = *s;
715     }
716
717     err = _gpgme_data_append_for_xml ( dh, buf, d - buf );
718     xfree (buf);
719     return err;
720 }
721
722
723
724
725
726
727