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