gpgme/
[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
8  * it 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,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <sys/types.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 GpgmeError
61 _gpgme_decode_c_string (const char *src, char **destp)
62 {
63   char *dest;
64
65   /* We can malloc a buffer of the same length, because the converted
66      string will never be larger.  */
67   dest = xtrymalloc (strlen (src) + 1);
68   if (!dest)
69     return mk_error (Out_Of_Core);
70
71   *destp = dest;
72
73   while (*src)
74     {
75       if (*src != '\\')
76         *(dest++) = *(src++);
77       else if (src[1] == '\\')
78         {
79           src++;
80           *(dest++) = *(src++); 
81         }
82       else if (src[1] == 'n')
83         {
84           src += 2;
85           *(dest++) = '\n'; 
86         }
87       else if (src[1] == 'r')
88         {
89           src += 2;
90           *(dest++) = '\r'; 
91         }
92       else if (src[1] == 'v')
93         {
94           src += 2;
95           *(dest++) = '\v'; 
96         }
97       else if (src[1] == 'b')
98         {
99           src += 2;
100           *(dest++) = '\b'; 
101         }
102       else if (src[1] == '0')
103         {
104           /* Hmmm: no way to express this */
105           src += 2;
106           *(dest++) = '\\';
107           *(dest++) = '\0'; 
108         }
109       else if (src[1] == 'x' && isxdigit (src[2]) && isxdigit (src[3]))
110         {
111           int val = _gpgme_hextobyte (&src[2]);
112           if (val == -1)
113             {
114               /* Should not happen.  */
115               *(dest++) = *(src++);
116               *(dest++) = *(src++);
117               *(dest++) = *(src++);
118               *(dest++) = *(src++);
119             }
120           else
121             {
122               if (!val)
123                 {
124                   *(dest++) = '\\';
125                   *(dest++) = '\0'; 
126                 }
127               else 
128                 *(byte*)dest++ = val;
129               src += 4;
130             }
131         }
132       else
133         {
134           /* should not happen */
135           src++;
136           *(dest++) = '\\'; 
137           *(dest++) = *(src++);
138         } 
139     }
140   *(dest++) = 0;
141
142   return 0;
143 }
144
145 \f
146 GpgmeError
147 _gpgme_data_append (GpgmeData dh, const char *buffer, size_t length)
148 {
149   if (!dh || !buffer)
150     return mk_error (Invalid_Value);
151
152   do
153     {
154       ssize_t amt = gpgme_data_write (dh, buffer, length);
155       if (amt == 0 || (amt < 0 && errno != EINTR))
156         return mk_error (File_Error);
157       buffer += amt;
158       length -= amt;
159     }
160   while (length > 0);
161
162   return 0;
163 }
164
165
166 GpgmeError
167 _gpgme_data_append_string (GpgmeData dh, const char *str)
168 {
169   if (!str)
170     return 0;
171
172   return _gpgme_data_append (dh, str, strlen (str));
173 }
174
175
176 GpgmeError
177 _gpgme_data_append_for_xml (GpgmeData dh, const char *buffer, size_t len)
178 {
179   const char *text, *str;
180   size_t count;
181   int err = 0;
182
183   if (!dh || !buffer)
184     return mk_error (Invalid_Value);
185
186   do
187     {
188       text = NULL;
189       str = buffer;
190       for (count = len; count && !text; str++, count--)
191         {
192           if (*str == '<')
193             text = "&lt;";
194           else if (*str == '>')
195             text = "&gt;";  /* Not sure whether this is really needed.  */
196           else if (*str == '&')
197             text = "&amp;";
198           else if (!*str)
199             text = "&#00;";
200         }
201       if (text)
202         {
203           str--;
204           count++;
205         }
206       if (str != buffer)
207         err = _gpgme_data_append (dh, buffer, str - buffer);
208       if (!err && text)
209         {
210           err = _gpgme_data_append_string (dh, text);
211           str++;
212           count--;
213         }
214       buffer = str;
215       len = count;
216     }
217   while (!err && len);
218   return err;
219 }
220
221
222 /* Append a string to DATA and convert it so that the result will be
223    valid XML.  */
224 GpgmeError
225 _gpgme_data_append_string_for_xml (GpgmeData dh, const char *str)
226 {
227   return _gpgme_data_append_for_xml (dh, str, strlen (str));
228 }
229
230
231 /* Append a string with percent style (%XX) escape characters as
232    XML.  */
233 GpgmeError
234 _gpgme_data_append_percentstring_for_xml (GpgmeData dh, const char *str)
235 {
236   const byte *src;
237   byte *buf, *dst;
238   int val;
239   GpgmeError err;
240
241   buf = xtrymalloc (strlen (str));
242   dst = buf;
243   for (src = str; *src; src++)
244     {
245       if (*src == '%' && (val = _gpgme_hextobyte (src + 1)) != -1)
246         {
247           *dst++ = val;
248           src += 2;
249         }
250       else
251         *dst++ = *src;
252     }
253
254   err = _gpgme_data_append_for_xml (dh, buf, dst - buf);
255   xfree (buf);
256   return err;
257 }