2003-01-29 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / conversion.c
1 /* conversion.c - String conversion helper functions.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002 g10 Code GmbH
4  
5    This file is part of GPGME.
6
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <string.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #include <stdlib.h>
30
31 #include "gpgme.h"
32 #include "util.h"
33
34
35 int
36 _gpgme_hextobyte (const byte *str)
37 {
38   int val = 0;
39   int i;
40
41 #define NROFHEXDIGITS 2
42   for (i = 0; i < NROFHEXDIGITS; i++)
43     {
44       if (*str >= '0' && *str <= '9')
45         val += *str - '0';
46       else if (*str >= 'A' && *str <= 'F')
47         val += 10 + *str - 'A';
48       else if (*str >= 'a' && *str <= 'f')
49         val += 10 + *str - 'a';
50       else
51         return -1;
52       if (i < NROFHEXDIGITS - 1)
53         val *= 16;
54       str++;
55     }
56   return val;
57 }
58
59
60 /* Decode the C formatted string SRC and store the result in the
61    buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
62    large enough buffer is allocated with malloc and *DESTP is set to
63    the result.  Currently, LEN is only used to specify if allocation
64    is desired or not, the caller is expected to make sure that *DESTP
65    is large enough if LEN is not zero.  */
66 GpgmeError
67 _gpgme_decode_c_string (const char *src, char **destp, int len)
68 {
69   char *dest;
70
71   if (len)
72     dest = *destp;
73   else
74     {
75       /* We can malloc a buffer of the same length, because the converted
76          string will never be larger.  */
77       dest = malloc (strlen (src) + 1);
78       if (!dest)
79         return GPGME_Out_Of_Core;
80
81       *destp = dest;
82     }
83
84   while (*src)
85     {
86       if (*src != '\\')
87         *(dest++) = *(src++);
88       else if (src[1] == '\\')
89         {
90           src++;
91           *(dest++) = *(src++); 
92         }
93       else if (src[1] == 'n')
94         {
95           src += 2;
96           *(dest++) = '\n'; 
97         }
98       else if (src[1] == 'r')
99         {
100           src += 2;
101           *(dest++) = '\r'; 
102         }
103       else if (src[1] == 'v')
104         {
105           src += 2;
106           *(dest++) = '\v'; 
107         }
108       else if (src[1] == 'b')
109         {
110           src += 2;
111           *(dest++) = '\b'; 
112         }
113       else if (src[1] == '0')
114         {
115           /* Hmmm: no way to express this */
116           src += 2;
117           *(dest++) = '\\';
118           *(dest++) = '\0'; 
119         }
120       else if (src[1] == 'x' && isxdigit (src[2]) && isxdigit (src[3]))
121         {
122           int val = _gpgme_hextobyte (&src[2]);
123           if (val == -1)
124             {
125               /* Should not happen.  */
126               *(dest++) = *(src++);
127               *(dest++) = *(src++);
128               *(dest++) = *(src++);
129               *(dest++) = *(src++);
130             }
131           else
132             {
133               if (!val)
134                 {
135                   *(dest++) = '\\';
136                   *(dest++) = '\0'; 
137                 }
138               else 
139                 *(byte*)dest++ = val;
140               src += 4;
141             }
142         }
143       else
144         {
145           /* should not happen */
146           src++;
147           *(dest++) = '\\'; 
148           *(dest++) = *(src++);
149         } 
150     }
151   *(dest++) = 0;
152
153   return 0;
154 }
155
156 \f
157 GpgmeError
158 _gpgme_data_append (GpgmeData dh, const char *buffer, size_t length)
159 {
160   if (!dh || !buffer)
161     return GPGME_Invalid_Value;
162
163   do
164     {
165       ssize_t amt = gpgme_data_write (dh, buffer, length);
166       if (amt == 0 || (amt < 0 && errno != EINTR))
167         return GPGME_File_Error;
168       buffer += amt;
169       length -= amt;
170     }
171   while (length > 0);
172
173   return 0;
174 }
175
176
177 GpgmeError
178 _gpgme_data_append_string (GpgmeData dh, const char *str)
179 {
180   if (!str)
181     return 0;
182
183   return _gpgme_data_append (dh, str, strlen (str));
184 }
185
186
187 GpgmeError
188 _gpgme_data_append_for_xml (GpgmeData dh, const char *buffer, size_t len)
189 {
190   const char *text, *str;
191   size_t count;
192   int err = 0;
193
194   if (!dh || !buffer)
195     return GPGME_Invalid_Value;
196
197   do
198     {
199       text = NULL;
200       str = buffer;
201       for (count = len; count && !text; str++, count--)
202         {
203           if (*str == '<')
204             text = "&lt;";
205           else if (*str == '>')
206             text = "&gt;";  /* Not sure whether this is really needed.  */
207           else if (*str == '&')
208             text = "&amp;";
209           else if (!*str)
210             text = "&#00;";
211         }
212       if (text)
213         {
214           str--;
215           count++;
216         }
217       if (str != buffer)
218         err = _gpgme_data_append (dh, buffer, str - buffer);
219       if (!err && text)
220         {
221           err = _gpgme_data_append_string (dh, text);
222           str++;
223           count--;
224         }
225       buffer = str;
226       len = count;
227     }
228   while (!err && len);
229   return err;
230 }
231
232
233 /* Append a string to DATA and convert it so that the result will be
234    valid XML.  */
235 GpgmeError
236 _gpgme_data_append_string_for_xml (GpgmeData dh, const char *str)
237 {
238   return _gpgme_data_append_for_xml (dh, str, strlen (str));
239 }
240
241
242 /* Append a string with percent style (%XX) escape characters as
243    XML.  */
244 GpgmeError
245 _gpgme_data_append_percentstring_for_xml (GpgmeData dh, const char *str)
246 {
247   const byte *src;
248   byte *buf, *dst;
249   int val;
250   GpgmeError err;
251
252   buf = malloc (strlen (str));
253   dst = buf;
254   for (src = str; *src; src++)
255     {
256       if (*src == '%' && (val = _gpgme_hextobyte (src + 1)) != -1)
257         {
258           *dst++ = val;
259           src += 2;
260         }
261       else
262         *dst++ = *src;
263     }
264
265   err = _gpgme_data_append_for_xml (dh, buf, dst - buf);
266   free (buf);
267   return err;
268 }