2009-10-30 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / src / conversion.c
1 /* conversion.c - String conversion helper functions.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2007 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 Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (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    Lesser General Public License for more details.
16    
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 /* Solaris 8 needs sys/types.h before time.h.  */
29 #include <sys/types.h>
30 #include <time.h>
31 #include <errno.h>
32
33 #include "gpgme.h"
34 #include "util.h"
35 #include "debug.h"
36
37 #define atoi_1(p)   (*(p) - '0' )
38 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
39 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
40
41
42 \f
43 /* Convert two hexadecimal digits from STR to the value they
44    represent.  Returns -1 if one of the characters is not a
45    hexadecimal digit.  */
46 int
47 _gpgme_hextobyte (const char *str)
48 {
49   int val = 0;
50   int i;
51
52 #define NROFHEXDIGITS 2
53   for (i = 0; i < NROFHEXDIGITS; i++)
54     {
55       if (*str >= '0' && *str <= '9')
56         val += *str - '0';
57       else if (*str >= 'A' && *str <= 'F')
58         val += 10 + *str - 'A';
59       else if (*str >= 'a' && *str <= 'f')
60         val += 10 + *str - 'a';
61       else
62         return -1;
63       if (i < NROFHEXDIGITS - 1)
64         val *= 16;
65       str++;
66     }
67   return val;
68 }
69
70
71 /* Decode the C formatted string SRC and store the result in the
72    buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
73    large enough buffer is allocated with malloc and *DESTP is set to
74    the result.  Currently, LEN is only used to specify if allocation
75    is desired or not, the caller is expected to make sure that *DESTP
76    is large enough if LEN is not zero.  */
77 gpgme_error_t
78 _gpgme_decode_c_string (const char *src, char **destp, size_t len)
79 {
80   char *dest;
81
82   /* Set up the destination buffer.  */
83   if (len)
84     {
85       if (len < strlen (src) + 1)
86         return gpg_error (GPG_ERR_INTERNAL);
87
88       dest = *destp;
89     }
90   else
91     {
92       /* The converted string will never be larger than the original
93          string.  */
94       dest = malloc (strlen (src) + 1);
95       if (!dest)
96         return gpg_error_from_errno (errno);
97
98       *destp = dest;
99     }
100
101   /* Convert the string.  */
102   while (*src)
103     {
104       if (*src != '\\')
105         {
106           *(dest++) = *(src++);
107           continue;
108         }
109
110       switch (src[1])
111         {
112 #define DECODE_ONE(match,result)        \
113         case match:                     \
114           src += 2;                     \
115           *(dest++) = result;           \
116           break;
117
118           DECODE_ONE ('\'', '\'');
119           DECODE_ONE ('\"', '\"');
120           DECODE_ONE ('\?', '\?');
121           DECODE_ONE ('\\', '\\');
122           DECODE_ONE ('a', '\a');
123           DECODE_ONE ('b', '\b');
124           DECODE_ONE ('f', '\f');
125           DECODE_ONE ('n', '\n');
126           DECODE_ONE ('r', '\r');
127           DECODE_ONE ('t', '\t');
128           DECODE_ONE ('v', '\v');
129
130         case 'x':
131           {
132             int val = _gpgme_hextobyte (&src[2]);
133
134             if (val == -1)
135               {
136                 /* Should not happen.  */
137                 *(dest++) = *(src++);
138                 *(dest++) = *(src++);
139                 if (*src)
140                   *(dest++) = *(src++);
141                 if (*src)
142                   *(dest++) = *(src++);
143               }
144             else
145               {
146                 if (!val)
147                   {
148                     /* A binary zero is not representable in a C
149                        string.  */
150                     *(dest++) = '\\';
151                     *(dest++) = '0'; 
152                   }
153                 else 
154                   *((unsigned char *) dest++) = val;
155                 src += 4;
156               }
157           }
158           break;
159
160         default:
161           {
162             /* Should not happen.  */
163             *(dest++) = *(src++);
164             *(dest++) = *(src++);
165           }
166         } 
167     }
168   *(dest++) = 0;
169
170   return 0;
171 }
172
173
174 /* Decode the percent escaped string SRC and store the result in the
175    buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
176    large enough buffer is allocated with malloc and *DESTP is set to
177    the result.  Currently, LEN is only used to specify if allocation
178    is desired or not, the caller is expected to make sure that *DESTP
179    is large enough if LEN is not zero.  If BINARY is 1, then '\0'
180    characters are allowed in the output.  */
181 gpgme_error_t
182 _gpgme_decode_percent_string (const char *src, char **destp, size_t len,
183                               int binary)
184 {
185   char *dest;
186
187   /* Set up the destination buffer.  */
188   if (len)
189     {
190       if (len < strlen (src) + 1)
191         return gpg_error (GPG_ERR_INTERNAL);
192
193       dest = *destp;
194     }
195   else
196     {
197       /* The converted string will never be larger than the original
198          string.  */
199       dest = malloc (strlen (src) + 1);
200       if (!dest)
201         return gpg_error_from_errno (errno);
202
203       *destp = dest;
204     }
205
206   /* Convert the string.  */
207   while (*src)
208     {
209       if (*src != '%')
210         {
211           *(dest++) = *(src++);
212           continue;
213         }
214       else
215         {
216           int val = _gpgme_hextobyte (&src[1]);
217           
218           if (val == -1)
219             {
220               /* Should not happen.  */
221               *(dest++) = *(src++);
222               if (*src)
223                 *(dest++) = *(src++);
224               if (*src)
225                 *(dest++) = *(src++);
226             }
227           else
228             {
229               if (!val && !binary)
230                 {
231                   /* A binary zero is not representable in a C
232                      string.  */
233                   *(dest++) = '\\';
234                   *(dest++) = '0'; 
235                 }
236               else 
237                 *((unsigned char *) dest++) = val;
238               src += 3;
239             }
240         }
241     }
242   *(dest++) = 0;
243
244   return 0;
245 }
246
247
248 /* Encode the string SRC with percent escaping and store the result in
249    the buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
250    large enough buffer is allocated with malloc and *DESTP is set to
251    the result.  Currently, LEN is only used to specify if allocation
252    is desired or not, the caller is expected to make sure that *DESTP
253    is large enough if LEN is not zero.  If BINARY is 1, then '\0'
254    characters are allowed in the output.  */
255 gpgme_error_t
256 _gpgme_encode_percent_string (const char *src, char **destp, size_t len)
257 {
258   size_t destlen;
259   char *dest;
260   const char *str;
261
262   destlen = 0;
263   str = src;
264   /* We percent-escape the + character because the user might need a
265      "percent plus" escaped string (special gpg format).  But we
266      percent-escape the space character, which works with and without
267      the special plus format.  */
268   while (*str)
269     {
270       if (*str == '+' || *str == '\"' || *str == '%' 
271           || *(const unsigned char *)str <= 0x20)
272         destlen += 3;
273       else
274         destlen++;
275       str++;
276     }
277   /* Terminating nul byte.  */
278   destlen++;
279
280   /* Set up the destination buffer.  */
281   if (len)
282     {
283       if (len < destlen);
284         return gpg_error (GPG_ERR_INTERNAL);
285
286       dest = *destp;
287     }
288   else
289     {
290       /* The converted string will never be larger than the original
291          string.  */
292       dest = malloc (destlen);
293       if (!dest)
294         return gpg_error_from_errno (errno);
295
296       *destp = dest;
297     }
298
299   /* Convert the string.  */
300   while (*src)
301     {
302       if (*src == '+' || *src == '\"' || *src == '%' 
303           || *(const unsigned char *)src <= 0x20)
304         {
305           snprintf (dest, 4, "%%%02X", *(unsigned char *)src);
306           dest += 3;
307         }
308       else
309         *(dest++) = *src;
310       src++;
311     }
312   *(dest++) = 0;
313
314   return 0;
315 }
316
317
318 /* Parse the string TIMESTAMP into a time_t.  The string may either be
319    seconds since Epoch or in the ISO 8601 format like
320    "20390815T143012".  Returns 0 for an empty string or seconds since
321    Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
322    point to the next non-parsed character in TIMESTRING. */
323 time_t
324 _gpgme_parse_timestamp (const char *timestamp, char **endp)
325 {
326   /* Need to skip leading spaces, because that is what strtoul does
327      but not our ISO 8601 checking code. */
328   while (*timestamp && *timestamp== ' ')
329     timestamp++;
330   if (!*timestamp)
331     return 0;
332
333   if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
334     {
335       struct tm buf;
336       int year;
337
338       year = atoi_4 (timestamp);
339       if (year < 1900)
340         return (time_t)(-1);
341
342       /* Fixme: We would better use a configure test to see whether
343          mktime can handle dates beyond 2038. */
344       if (sizeof (time_t) <= 4 && year >= 2038)
345         return (time_t)2145914603; /* 2037-12-31 23:23:23 */
346
347       memset (&buf, 0, sizeof buf);
348       buf.tm_year = year - 1900;
349       buf.tm_mon = atoi_2 (timestamp+4) - 1; 
350       buf.tm_mday = atoi_2 (timestamp+6);
351       buf.tm_hour = atoi_2 (timestamp+9);
352       buf.tm_min = atoi_2 (timestamp+11);
353       buf.tm_sec = atoi_2 (timestamp+13);
354
355       if (endp)
356         *endp = (char*)(timestamp + 15);
357 #ifdef HAVE_TIMEGM
358       return timegm (&buf);
359 #else
360       {
361         time_t tim;
362         
363         putenv ("TZ=UTC");
364         tim = mktime (&buf);
365 #ifdef __GNUC__
366 #warning fixme: we must somehow reset TZ here.  It is not threadsafe anyway.
367 #endif
368         return tim;
369       }
370 #endif /* !HAVE_TIMEGM */
371     }
372   else
373     return (time_t)strtoul (timestamp, endp, 10);
374 }