doc/
[gpgme.git] / gpgme / conversion.c
1 /* conversion.c - String conversion helper functions.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 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 <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include "gpgme.h"
30 #include "util.h"
31
32 \f
33 /* Convert two hexadecimal digits from STR to the value they
34    represent.  Returns -1 if one of the characters is not a
35    hexadecimal digit.  */
36 int
37 _gpgme_hextobyte (const unsigned char *str)
38 {
39   int val = 0;
40   int i;
41
42 #define NROFHEXDIGITS 2
43   for (i = 0; i < NROFHEXDIGITS; i++)
44     {
45       if (*str >= '0' && *str <= '9')
46         val += *str - '0';
47       else if (*str >= 'A' && *str <= 'F')
48         val += 10 + *str - 'A';
49       else if (*str >= 'a' && *str <= 'f')
50         val += 10 + *str - 'a';
51       else
52         return -1;
53       if (i < NROFHEXDIGITS - 1)
54         val *= 16;
55       str++;
56     }
57   return val;
58 }
59
60
61 /* Decode the C formatted string SRC and store the result in the
62    buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
63    large enough buffer is allocated with malloc and *DESTP is set to
64    the result.  Currently, LEN is only used to specify if allocation
65    is desired or not, the caller is expected to make sure that *DESTP
66    is large enough if LEN is not zero.  */
67 gpgme_error_t
68 _gpgme_decode_c_string (const char *src, char **destp, size_t len)
69 {
70   char *dest;
71
72   /* Set up the destination buffer.  */
73   if (len)
74     {
75       if (len < strlen (src) + 1)
76         return gpg_error (GPG_ERR_INTERNAL);
77
78       dest = *destp;
79     }
80   else
81     {
82       /* The converted string will never be larger than the original
83          string.  */
84       dest = malloc (strlen (src) + 1);
85       if (!dest)
86         return gpg_error_from_errno (errno);
87
88       *destp = dest;
89     }
90
91   /* Convert the string.  */
92   while (*src)
93     {
94       if (*src != '\\')
95         {
96           *(dest++) = *(src++);
97           continue;
98         }
99
100       switch (src[1])
101         {
102 #define DECODE_ONE(match,result)        \
103         case match:                     \
104           src += 2;                     \
105           *(dest++) = result;           \
106           break;
107
108           DECODE_ONE ('\'', '\'');
109           DECODE_ONE ('\"', '\"');
110           DECODE_ONE ('\?', '\?');
111           DECODE_ONE ('\\', '\\');
112           DECODE_ONE ('a', '\a');
113           DECODE_ONE ('b', '\b');
114           DECODE_ONE ('f', '\f');
115           DECODE_ONE ('n', '\n');
116           DECODE_ONE ('r', '\r');
117           DECODE_ONE ('t', '\t');
118           DECODE_ONE ('v', '\v');
119
120         case 'x':
121           {
122             int val = _gpgme_hextobyte (&src[2]);
123
124             if (val == -1)
125               {
126                 /* Should not happen.  */
127                 *(dest++) = *(src++);
128                 *(dest++) = *(src++);
129                 if (*src)
130                   *(dest++) = *(src++);
131                 if (*src)
132                   *(dest++) = *(src++);
133               }
134             else
135               {
136                 if (!val)
137                   {
138                     /* A binary zero is not representable in a C
139                        string.  */
140                     *(dest++) = '\\';
141                     *(dest++) = '0'; 
142                   }
143                 else 
144                   *((unsigned char *) dest++) = val;
145                 src += 4;
146               }
147           }
148           break;
149
150         default:
151           {
152             /* Should not happen.  */
153             *(dest++) = *(src++);
154             *(dest++) = *(src++);
155           }
156         } 
157     }
158   *(dest++) = 0;
159
160   return 0;
161 }
162
163
164 /* Decode the percent escaped string SRC and store the result in the
165    buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
166    large enough buffer is allocated with malloc and *DESTP is set to
167    the result.  Currently, LEN is only used to specify if allocation
168    is desired or not, the caller is expected to make sure that *DESTP
169    is large enough if LEN is not zero.  */
170 gpgme_error_t
171 _gpgme_decode_percent_string (const char *src, char **destp, size_t len)
172 {
173   char *dest;
174
175   /* Set up the destination buffer.  */
176   if (len)
177     {
178       if (len < strlen (src) + 1)
179         return gpg_error (GPG_ERR_INTERNAL);
180
181       dest = *destp;
182     }
183   else
184     {
185       /* The converted string will never be larger than the original
186          string.  */
187       dest = malloc (strlen (src) + 1);
188       if (!dest)
189         return gpg_error_from_errno (errno);
190
191       *destp = dest;
192     }
193
194   /* Convert the string.  */
195   while (*src)
196     {
197       if (*src != '%')
198         {
199           *(dest++) = *(src++);
200           continue;
201         }
202       else
203         {
204           int val = _gpgme_hextobyte (&src[1]);
205           
206           if (val == -1)
207             {
208               /* Should not happen.  */
209               *(dest++) = *(src++);
210               if (*src)
211                 *(dest++) = *(src++);
212               if (*src)
213                 *(dest++) = *(src++);
214             }
215           else
216             {
217               if (!val)
218                 {
219                   /* A binary zero is not representable in a C
220                      string.  */
221                   *(dest++) = '\\';
222                   *(dest++) = '0'; 
223                 }
224               else 
225                 *((unsigned char *) dest++) = val;
226               src += 3;
227             }
228         }
229     }
230   *(dest++) = 0;
231
232   return 0;
233 }
234
235 \f
236 static struct
237 {
238   char *name;
239   gpgme_error_t err;
240 } gnupg_errors[] =
241   {
242     { "EOF", GPG_ERR_EOF },
243     { "No_Error", GPG_ERR_NO_ERROR },
244     { "General_Error", GPG_ERR_GENERAL },
245     { "Out_Of_Core", GPG_ERR_ENOMEM },
246     { "Invalid_Value", GPG_ERR_INV_VALUE },
247     { "IO_Error", GPG_ERR_GENERAL },
248     { "Resource_Limit", GPG_ERR_RESOURCE_LIMIT },
249     { "Internal_Error", GPG_ERR_INTERNAL },
250     { "Bad_Certificate", GPG_ERR_BAD_CERT },
251     { "Bad_Certificate_Chain", GPG_ERR_BAD_CERT_CHAIN},
252     { "Missing_Certificate", GPG_ERR_MISSING_CERT },
253     { "No_Data", GPG_ERR_NO_DATA },
254     { "Bad_Signature", GPG_ERR_BAD_SIGNATURE },
255     { "Not_Implemented", GPG_ERR_NOT_IMPLEMENTED },
256     { "Conflict", GPG_ERR_CONFLICT },
257     { "Bug", GPG_ERR_BUG },
258     { "Read_Error", GPG_ERR_GENERAL },
259     { "Write_Error", GPG_ERR_GENERAL },
260     { "Invalid_Line", GPG_ERR_GENERAL },
261     { "Incomplete_Line", GPG_ERR_INCOMPLETE_LINE },
262     { "Invalid_Response", GPG_ERR_INV_RESPONSE },
263     { "Agent_Error", GPG_ERR_AGENT },
264     { "No_Public_Key", GPG_ERR_NO_PUBKEY },
265     { "No_Secret_Key", GPG_ERR_NO_SECKEY },
266     { "File_Open_Error", GPG_ERR_GENERAL },
267     { "File_Create_Error", GPG_ERR_GENERAL },
268     { "File_Error", GPG_ERR_GENERAL },
269     { "Not_Supported", GPG_ERR_NOT_SUPPORTED },
270     { "Invalid_Data", GPG_ERR_INV_DATA },
271     { "Assuan_Server_Fault", GPG_ERR_ASSUAN_SERVER_FAULT },
272     { "Assuan_Error", GPG_ERR_ASSUAN },
273     { "Invalid_Session_Key", GPG_ERR_INV_SESSION_KEY },
274     { "Invalid_Sexp", GPG_ERR_INV_SEXP },
275     { "Unsupported_Algorithm", GPG_ERR_UNSUPPORTED_ALGORITHM },
276     { "No_PIN_Entry", GPG_ERR_NO_PIN_ENTRY },
277     { "PIN_Entry_Error", GPG_ERR_NO_PIN_ENTRY },
278     { "Bad_PIN", GPG_ERR_BAD_PIN },
279     { "Bad_Passphrase", GPG_ERR_BAD_PASSPHRASE },
280     { "Invalid_Name", GPG_ERR_INV_NAME },
281     { "Bad_Public_Key", GPG_ERR_BAD_PUBKEY },
282     { "Bad_Secret_Key", GPG_ERR_BAD_SECKEY },
283     { "Bad_Data", GPG_ERR_BAD_DATA },
284     { "Invalid_Parameter", GPG_ERR_INV_PARAMETER },
285     { "Tribute_to_D_A", GPG_ERR_TRIBUTE_TO_D_A },
286     { "No_Dirmngr", GPG_ERR_NO_DIRMNGR },
287     { "Dirmngr_Error", GPG_ERR_DIRMNGR },
288     { "Certificate_Revoked", GPG_ERR_CERT_REVOKED },
289     { "No_CRL_Known", GPG_ERR_NO_CRL_KNOWN },
290     { "CRL_Too_Old", GPG_ERR_CRL_TOO_OLD },
291     { "Line_Too_Long", GPG_ERR_LINE_TOO_LONG },
292     { "Not_Trusted", GPG_ERR_NOT_TRUSTED },
293     { "Canceled", GPG_ERR_CANCELED },
294     { "Bad_CA_Certificate", GPG_ERR_BAD_CA_CERT },
295     { "Certificate_Expired", GPG_ERR_CERT_EXPIRED },
296     { "Certificate_Too_Young", GPG_ERR_CERT_TOO_YOUNG },
297     { "Unsupported_Certificate", GPG_ERR_UNSUPPORTED_CERT },
298     { "Unknown_Sexp", GPG_ERR_UNKNOWN_SEXP },
299     { "Unsupported_Protection", GPG_ERR_UNSUPPORTED_PROTECTION },
300     { "Corrupted_Protection", GPG_ERR_CORRUPTED_PROTECTION },
301     { "Ambiguous_Name", GPG_ERR_AMBIGUOUS_NAME },
302     { "Card_Error", GPG_ERR_CARD },
303     { "Card_Reset", GPG_ERR_CARD_RESET },
304     { "Card_Removed", GPG_ERR_CARD_REMOVED },
305     { "Invalid_Card", GPG_ERR_INV_CARD },
306     { "Card_Not_Present", GPG_ERR_CARD_NOT_PRESENT },
307     { "No_PKCS15_App", GPG_ERR_NO_PKCS15_APP },
308     { "Not_Confirmed", GPG_ERR_NOT_CONFIRMED },
309     { "Configuration_Error", GPG_ERR_CONFIGURATION },
310     { "No_Policy_Match", GPG_ERR_NO_POLICY_MATCH },
311     { "Invalid_Index", GPG_ERR_INV_INDEX },
312     { "Invalid_Id", GPG_ERR_INV_ID },
313     { "No_Scdaemon", GPG_ERR_NO_SCDAEMON },
314     { "Scdaemon_Error", GPG_ERR_SCDAEMON },
315     { "Unsupported_Protocol", GPG_ERR_UNSUPPORTED_PROTOCOL },
316     { "Bad_PIN_Method", GPG_ERR_BAD_PIN_METHOD },
317     { "Card_Not_Initialized", GPG_ERR_CARD_NOT_INITIALIZED },
318     { "Unsupported_Operation", GPG_ERR_UNSUPPORTED_OPERATION },
319     { "Wrong_Key_Usage", GPG_ERR_WRONG_KEY_USAGE }
320   };
321     
322
323 gpgme_error_t
324 _gpgme_map_gnupg_error (char *err)
325 {
326   unsigned int i;
327
328   for (i = 0; i < DIM (gnupg_errors); i++)
329     if (!strcmp (gnupg_errors[i].name, err))
330       return gpg_err_make (GPG_ERR_SOURCE_GPG, gnupg_errors[i].err);
331
332   return gpg_err_make (GPG_ERR_SOURCE_GPG, GPG_ERR_GENERAL);
333 }