Notation stuff added
[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
26 #include "util.h"
27 #include "context.h"
28 #include "ops.h"
29
30 #define ALLOC_CHUNK 1024
31 #define my_isdigit(a)  ( (a) >='0' && (a) <= '9' )
32 #define my_isxdigit(a) ( my_isdigit((a))               \
33                          || ((a) >= 'A' && (a) <= 'F') \
34                          || ((a) >= 'f' && (a) <= 'f') )
35
36
37
38 /**
39  * gpgme_data_new:
40  * @r_dh:   Returns a new data object.
41  * @buffer: If not NULL, used to initialize the data object.
42  * @size: Size of the buffer
43  * @copy: Flag wether a copy of the buffer should be used.
44  * 
45  * Create a new data object and optionally initialize with data
46  * from the memory.  A @copy with value %TRUE creates a copy of the
47  * memory, a value of %FALSE uses the original memory of @buffer and the
48  * caller has to make sure that this buffer is valid until gpgme_release_data()
49  * is called.
50  * 
51  * Return value: 
52  **/
53 GpgmeError
54 gpgme_data_new ( GpgmeData *r_dh, const char *buffer, size_t size, int copy )
55 {
56     GpgmeData dh;
57
58     *r_dh = NULL;
59     dh = xtrycalloc ( 1, sizeof *dh );
60     if (!dh)
61         return mk_error (Out_Of_Core);
62     if ( buffer ) {
63         dh->len  = size;
64         if (copy) {
65             dh->private_buffer = xtrymalloc ( size );
66             if ( !dh->private_buffer ) {
67                 xfree (dh);
68                 return mk_error (Out_Of_Core);
69             }
70             dh->private_len = size;
71             memcpy (dh->private_buffer, buffer, size );
72             dh->data = dh->private_buffer;
73             dh->writepos = size;
74         }
75         else {
76             dh->data = buffer;
77         }
78         dh->type = GPGME_DATA_TYPE_MEM;
79     }
80     dh->mode = GPGME_DATA_MODE_INOUT; 
81     *r_dh = dh;
82     return 0;
83 }
84
85 /**
86  * gpgme_data_release:
87  * @dh: Data object 
88  * 
89  * Release the data object @dh.  @dh may be NULL in which case nothing
90  * happens.
91  **/
92 void
93 gpgme_data_release ( GpgmeData dh )
94 {
95     if (dh) {
96         xfree (dh->private_buffer); 
97         xfree (dh);
98     }
99 }
100
101 char *
102 _gpgme_data_release_and_return_string ( GpgmeData dh )
103 {
104     char *val = NULL;
105
106     if (dh) {
107         if ( _gpgme_data_append ( dh, "", 0 ) ) /* append EOS */
108             xfree (dh->private_buffer );
109         else {
110             val = dh->private_buffer;
111             if ( !val && dh->data ) {
112                 val = xtrymalloc ( dh->len );
113                 if ( val )
114                     memcpy ( val, dh->data, dh->len );
115             }
116         }
117         xfree (dh);
118     }
119     return val;
120 }
121
122
123 GpgmeDataType
124 gpgme_data_get_type ( GpgmeData dh )
125 {
126     if ( !dh || !dh->data )
127         return GPGME_DATA_TYPE_NONE;
128             
129     return dh->type;
130 }
131
132 void 
133 _gpgme_data_set_mode ( GpgmeData dh, GpgmeDataMode mode )
134 {
135     assert (dh);
136     dh->mode = mode;
137 }
138
139
140 GpgmeDataMode
141 _gpgme_data_get_mode ( GpgmeData dh )
142 {
143     assert (dh);
144     return dh->mode;
145 }
146
147 GpgmeError
148 gpgme_data_rewind ( GpgmeData dh )
149 {
150     if ( !dh )
151         return mk_error (Invalid_Value);
152     /* Fixme: We should check whether rewinding does make sense for the
153      * data type */
154     dh->readpos = 0;
155     return 0;
156 }
157
158 GpgmeError
159 gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
160 {
161     size_t nbytes;
162
163     if ( !dh )
164         return mk_error (Invalid_Value);
165     nbytes = dh->len - dh->readpos;
166     if ( !nbytes ) {
167         *nread = 0;
168         return mk_error(EOF);
169     }
170     if (nbytes > length)
171         nbytes = length;
172     memcpy ( buffer, dh->data + dh->readpos, nbytes );
173     *nread = nbytes;
174     dh->readpos += nbytes;
175     return 0;
176
177
178 /* 
179  * This function does make sense when we know that it contains no nil chars.
180  */
181 char *
182 _gpgme_data_get_as_string ( GpgmeData dh )
183 {
184     char *val = NULL;
185
186     if (dh) {
187         val = xtrymalloc ( dh->len+1 );
188         if ( val ) {
189             memcpy ( val, dh->data, dh->len );
190             val[dh->len] = 0;
191         }
192     }
193     return val;
194 }
195
196
197
198 GpgmeError
199 _gpgme_data_append ( GpgmeData dh, const char *buffer, size_t length )
200 {
201     assert (dh);
202
203     if ( dh->type == GPGME_DATA_TYPE_NONE ) {
204         /* convert it to a mem data type */
205         assert (!dh->private_buffer);
206         dh->type = GPGME_DATA_TYPE_MEM;
207         dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length;
208         dh->private_buffer = xtrymalloc ( dh->private_len );
209         if (!dh->private_buffer) {
210             dh->private_len = 0;
211             return mk_error (Out_Of_Core);
212         }
213         dh->writepos = 0;
214         dh->data = dh->private_buffer;
215     }
216     else if ( dh->type != GPGME_DATA_TYPE_MEM ) 
217         return mk_error (Invalid_Type);
218     
219     if ( dh->mode != GPGME_DATA_MODE_INOUT 
220          && dh->mode != GPGME_DATA_MODE_IN  )
221         return mk_error (Invalid_Mode);
222
223     if ( !dh->private_buffer ) {
224         /* we have to copy it now */
225         assert (dh->data);
226         dh->private_len = dh->len+length;
227         if (dh->private_len < ALLOC_CHUNK)
228             dh->private_len = ALLOC_CHUNK;
229         dh->private_buffer = xtrymalloc ( dh->private_len );
230         if (!dh->private_buffer) {
231             dh->private_len = 0;
232             return mk_error (Out_Of_Core);
233         }
234         memcpy ( dh->private_buffer, dh->data, dh->len );
235         dh->writepos = dh->len;
236         dh->data = dh->private_buffer;
237     }
238
239     /* allocate more memory if needed */
240     if ( dh->writepos + length > dh->private_len ) {
241         char *p;
242         size_t newlen = dh->private_len
243                         + (dh->len < ALLOC_CHUNK? ALLOC_CHUNK : length);
244         p = xtryrealloc ( dh->private_buffer, newlen );
245         if ( !p ) 
246             return mk_error (Out_Of_Core);
247         dh->private_buffer = p;
248         dh->private_len = newlen;
249         dh->data = dh->private_buffer;
250         assert ( !(dh->writepos + length > dh->private_len) );      
251     }
252
253     memcpy ( dh->private_buffer + dh->writepos, buffer, length );
254     dh->writepos += length;
255     dh->len += length;
256
257     return 0;
258 }
259
260 GpgmeError
261 _gpgme_data_append_string ( GpgmeData dh, const char *s )
262 {
263     return _gpgme_data_append ( dh, s, s? strlen(s):0 );
264 }
265
266
267 GpgmeError
268 _gpgme_data_append_for_xml ( GpgmeData dh,
269                              const char *buffer, size_t len )
270 {
271     const char *text, *s;
272     size_t n;
273     int rc = 0; 
274        
275     if ( !dh || !buffer )
276         return mk_error (Invalid_Value);
277
278     do {
279         for (text=NULL, s=buffer, n=len; n && !text; s++, n-- ) {
280             if ( *s == '<' ) 
281                 text = "&lt;";
282             else if ( *s == '>' ) 
283                 text = "&gt;";  /* not sure whether this is really needed */
284             else if ( *s == '&' ) 
285                 text = "&amp;";
286             else if ( !*s )
287                 text = "&#00;";
288         }
289         if (text) {
290             s--; n++;
291         }
292         if (s != buffer) 
293             rc = _gpgme_data_append ( dh, buffer, s-buffer );
294         if ( !rc && text) {
295             rc = _gpgme_data_append_string ( dh, text );
296             s++; n--;
297         }
298         buffer = s;
299         len = n;
300     } while ( !rc && len );
301     return rc;
302 }
303
304
305 /*
306  * Append a string to DATA and convert it so that the result will be 
307  * valid XML. 
308  */
309 GpgmeError
310 _gpgme_data_append_string_for_xml ( GpgmeData dh, const char *string )
311 {
312     return _gpgme_data_append_for_xml ( dh, string, strlen (string) );
313 }
314
315
316 static int
317 hextobyte( const byte *s )
318 {
319     int c;
320
321     if( *s >= '0' && *s <= '9' )
322         c = 16 * (*s - '0');
323     else if( *s >= 'A' && *s <= 'F' )
324         c = 16 * (10 + *s - 'A');
325     else if( *s >= 'a' && *s <= 'f' )
326         c = 16 * (10 + *s - 'a');
327     else
328         return -1;
329     s++;
330     if( *s >= '0' && *s <= '9' )
331         c += *s - '0';
332     else if( *s >= 'A' && *s <= 'F' )
333         c += 10 + *s - 'A';
334     else if( *s >= 'a' && *s <= 'f' )
335         c += 10 + *s - 'a';
336     else
337         return -1;
338     return c;
339 }
340
341
342
343
344 /* 
345  * Append a string with percent style (%XX) escape characters as XML
346  */
347 GpgmeError
348 _gpgme_data_append_percentstring_for_xml ( GpgmeData dh, const char *string )
349 {
350     const byte *s;
351     byte *buf, *d;
352     int val;
353     GpgmeError err;
354
355     d = buf = xtrymalloc ( strlen (string) );
356     for (s=string; *s; s++ ) {
357         if ( *s == '%' && (val=hextobyte (s+1)) != -1 ) {
358             *d++ = val;
359             s += 2;
360         }
361         else
362             *d++ = *s;
363     }
364
365     err = _gpgme_data_append_for_xml ( dh, buf, d - buf );
366     xfree (buf);
367     return err;
368 }
369
370
371
372
373
374
375