2 * Copyright (C) 2000 Werner Koch (dd9jn)
4 * This file is part of GPGME.
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.
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.
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
26 #include <sys/types.h>
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') )
43 * @r_dh: returns the new data object
45 * Create a new data object without any content.
47 * Return value: An error value or 0 on success
50 gpgme_data_new ( GpgmeData *r_dh )
55 return mk_error (Invalid_Value);
57 dh = xtrycalloc ( 1, sizeof *dh );
59 return mk_error (Out_Of_Core);
60 dh->mode = GPGME_DATA_MODE_INOUT;
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.
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()
82 gpgme_data_new_from_mem ( GpgmeData *r_dh,
83 const char *buffer, size_t size, int copy )
89 return mk_error (Invalid_Value);
91 err = gpgme_data_new ( &dh );
96 dh->private_buffer = xtrymalloc ( size );
97 if ( !dh->private_buffer ) {
98 gpgme_data_release (dh);
99 return mk_error (Out_Of_Core);
101 dh->private_len = size;
102 memcpy (dh->private_buffer, buffer, size );
103 dh->data = dh->private_buffer;
109 dh->type = GPGME_DATA_TYPE_MEM;
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 )
124 if (!r_dh || !read_cb)
125 return mk_error (Invalid_Value);
127 err = gpgme_data_new ( &dh );
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;
140 * gpgme_data_new_from_file:
141 * @r_dh: returns the new data object
143 * @copy: Flag, whether the file should be copied.
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.
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.
153 gpgme_data_new_from_file ( GpgmeData *r_dh, const char *fname, int copy )
161 return mk_error (Invalid_Value);
163 /* We only support copy for now - in future we might want to honor the
164 * copy flag and just store a file pointer */
166 return mk_error (Not_Implemented);
168 return mk_error (Invalid_Value);
170 err = gpgme_data_new ( &dh );
174 fp = fopen (fname, "rb");
176 int save_errno = errno;
177 gpgme_data_release (dh);
179 return mk_error (File_Error);
182 if( fstat(fileno(fp), &st) ) {
183 int save_errno = errno;
185 gpgme_data_release (dh);
187 return mk_error (File_Error);
190 /* We should check the length of the file and don't allow for to
192 dh->private_buffer = xtrymalloc ( st.st_size );
193 if ( !dh->private_buffer ) {
195 gpgme_data_release (dh);
196 return mk_error (Out_Of_Core);
198 dh->private_len = st.st_size;
200 if ( fread ( dh->private_buffer, dh->private_len, 1, fp ) != 1 ) {
201 int save_errno = errno;
203 gpgme_data_release (dh);
205 return mk_error (File_Error);
210 dh->len = dh->private_len;
211 dh->data = dh->private_buffer;
212 dh->writepos = dh->len;
213 dh->type = GPGME_DATA_TYPE_MEM;
221 gpgme_data_new_from_filepart ( GpgmeData *r_dh, const char *fname, FILE *fp,
222 off_t offset, off_t length )
228 return mk_error (Invalid_Value);
230 if ( fname && fp ) /* these are mutual exclusive */
231 return mk_error (Invalid_Value);
233 return mk_error (Invalid_Value);
235 return mk_error (Invalid_Value);
237 err = gpgme_data_new ( &dh );
242 fp = fopen (fname, "rb");
244 int save_errno = errno;
245 gpgme_data_release (dh);
247 return mk_error (File_Error);
251 if ( fseek ( fp, (long)offset, SEEK_SET) ) {
252 int save_errno = errno;
255 gpgme_data_release (dh);
257 return mk_error (File_Error);
261 dh->private_buffer = xtrymalloc ( length );
262 if ( !dh->private_buffer ) {
265 gpgme_data_release (dh);
266 return mk_error (Out_Of_Core);
268 dh->private_len = length;
270 if ( fread ( dh->private_buffer, dh->private_len, 1, fp ) != 1 ) {
271 int save_errno = errno;
274 gpgme_data_release (dh);
276 return mk_error (File_Error);
282 dh->len = dh->private_len;
283 dh->data = dh->private_buffer;
284 dh->writepos = dh->len;
285 dh->type = GPGME_DATA_TYPE_MEM;
293 * gpgme_data_release:
296 * Release the data object @dh. @dh may be NULL in which case nothing
300 gpgme_data_release ( GpgmeData dh )
303 xfree (dh->private_buffer);
309 _gpgme_data_release_and_return_string ( GpgmeData dh )
314 if ( _gpgme_data_append ( dh, "", 0 ) ) /* append EOS */
315 xfree (dh->private_buffer );
317 val = dh->private_buffer;
318 if ( !val && dh->data ) {
319 val = xtrymalloc ( dh->len );
321 memcpy ( val, dh->data, dh->len );
330 * gpgme_data_release_and_get_mem:
331 * @dh: the data object
332 * @r_len: returns the length of the memory
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.
339 * Return value: a pointer to an allocated buffer of length @r_len.
342 gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len )
349 size_t len = dh->len;
350 val = dh->private_buffer;
351 if ( !val && dh->data ) {
352 val = xtrymalloc ( len );
354 memcpy ( val, dh->data, len );
365 * gpgme_data_get_type:
366 * @dh: the data object
368 * Get the type of the data object.
369 * Data types are prefixed with %GPGME_DATA_TYPE_
371 * Return value: the data type
374 gpgme_data_get_type ( GpgmeData dh )
376 if ( !dh || (!dh->data && !dh->read_cb))
377 return GPGME_DATA_TYPE_NONE;
383 _gpgme_data_set_mode ( GpgmeData dh, GpgmeDataMode mode )
391 _gpgme_data_get_mode ( GpgmeData dh )
399 * @dh: the data object
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
405 * Return value: An error code or 0 on success
408 gpgme_data_rewind ( GpgmeData dh )
411 return mk_error (Invalid_Value);
413 if (dh->type == GPGME_DATA_TYPE_MEM ) {
416 else if (dh->type == GPGME_DATA_TYPE_CB) {
417 dh->len = dh->readpos = 0;
419 /* FIXME: do a special call to the read function to trigger a rewind
423 return mk_error (General_Error);
429 * @dh: the data object
431 * @length: The length of that bufer
432 * @nread: Returns the number of bytes actually read.
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
440 * Return value: An errorcode or 0 on success, EOF is indcated by the
441 * error code GPGME_EOF.
444 gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
449 return mk_error (Invalid_Value);
450 if (dh->type == GPGME_DATA_TYPE_MEM ) {
451 nbytes = dh->len - dh->readpos;
454 return mk_error(EOF);
458 memcpy ( buffer, dh->data + dh->readpos, nbytes );
460 dh->readpos += nbytes;
462 else if (dh->type == GPGME_DATA_TYPE_CB) {
463 nbytes = dh->len - dh->readpos;
465 /* we have unread data - return this */
468 memcpy ( buffer, dh->data + dh->readpos, nbytes );
470 dh->readpos += nbytes;
472 else { /* get the data from the callback */
473 if (!dh->read_cb || dh->read_cb_eof) {
475 return mk_error (EOF);
477 if (dh->read_cb (dh->read_cb_value, buffer, length, nread )) {
480 return mk_error (EOF);
485 return mk_error (General_Error);
490 _gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length )
493 return mk_error (Invalid_Value);
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;
503 return mk_error (General_Error);
511 * This function does make sense when we know that it contains no nil chars.
514 _gpgme_data_get_as_string ( GpgmeData dh )
519 val = xtrymalloc ( dh->len+1 );
521 memcpy ( val, dh->data, dh->len );
532 * @buffer: data to be written to the data object
533 * @length: length o this data
535 * Write the content of @buffer to the data object @dh at the current write
538 * Return value: 0 on succress or an errorcode
541 gpgme_data_write ( GpgmeData dh, const char *buffer, size_t length )
544 return mk_error (Invalid_Value);
546 return _gpgme_data_append (dh, buffer, length );
551 _gpgme_data_append ( GpgmeData dh, const char *buffer, size_t length )
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) {
563 return mk_error (Out_Of_Core);
566 dh->data = dh->private_buffer;
568 else if ( dh->type != GPGME_DATA_TYPE_MEM )
569 return mk_error (Invalid_Type);
571 if ( dh->mode != GPGME_DATA_MODE_INOUT
572 && dh->mode != GPGME_DATA_MODE_IN )
573 return mk_error (Invalid_Mode);
575 if ( !dh->private_buffer ) {
576 /* we have to copy it now */
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) {
584 return mk_error (Out_Of_Core);
586 memcpy ( dh->private_buffer, dh->data, dh->len );
587 dh->writepos = dh->len;
588 dh->data = dh->private_buffer;
591 /* allocate more memory if needed */
592 if ( dh->writepos + length > dh->private_len ) {
594 size_t newlen = dh->private_len
595 + (dh->len < ALLOC_CHUNK? ALLOC_CHUNK : length);
596 p = xtryrealloc ( dh->private_buffer, newlen );
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) );
605 memcpy ( dh->private_buffer + dh->writepos, buffer, length );
606 dh->writepos += length;
613 _gpgme_data_append_string ( GpgmeData dh, const char *s )
615 return _gpgme_data_append ( dh, s, s? strlen(s):0 );
620 _gpgme_data_append_for_xml ( GpgmeData dh,
621 const char *buffer, size_t len )
623 const char *text, *s;
627 if ( !dh || !buffer )
628 return mk_error (Invalid_Value);
631 for (text=NULL, s=buffer, n=len; n && !text; s++, n-- ) {
634 else if ( *s == '>' )
635 text = ">"; /* not sure whether this is really needed */
636 else if ( *s == '&' )
645 rc = _gpgme_data_append ( dh, buffer, s-buffer );
647 rc = _gpgme_data_append_string ( dh, text );
652 } while ( !rc && len );
658 * Append a string to DATA and convert it so that the result will be
662 _gpgme_data_append_string_for_xml ( GpgmeData dh, const char *string )
664 return _gpgme_data_append_for_xml ( dh, string, strlen (string) );
669 hextobyte( const byte *s )
673 if( *s >= '0' && *s <= '9' )
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');
682 if( *s >= '0' && *s <= '9' )
684 else if( *s >= 'A' && *s <= 'F' )
686 else if( *s >= 'a' && *s <= 'f' )
697 * Append a string with percent style (%XX) escape characters as XML
700 _gpgme_data_append_percentstring_for_xml ( GpgmeData dh, const char *string )
707 d = buf = xtrymalloc ( strlen (string) );
708 for (s=string; *s; s++ ) {
709 if ( *s == '%' && (val=hextobyte (s+1)) != -1 ) {
717 err = _gpgme_data_append_for_xml ( dh, buf, d - buf );