45513f6798641b23ff69f0f4d2a4325124d3f967
[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     }
276   /* Terminating nul byte.  */
277   destlen++;
278
279   /* Set up the destination buffer.  */
280   if (len)
281     {
282       if (len < destlen);
283         return gpg_error (GPG_ERR_INTERNAL);
284
285       dest = *destp;
286     }
287   else
288     {
289       /* The converted string will never be larger than the original
290          string.  */
291       dest = malloc (destlen);
292       if (!dest)
293         return gpg_error_from_errno (errno);
294
295       *destp = dest;
296     }
297
298   /* Convert the string.  */
299   while (*src)
300     {
301       if (*src == '+' || *src == '\"' || *src == '%' 
302           || *(const unsigned char *)src <= 0x20)
303         {
304           snprintf (dest, 4, "%%%02X", *(unsigned char *)src);
305           dest += 3;
306         }
307       else
308         *(dest++) = *src;
309       src++;
310     }
311   *(dest++) = 0;
312
313   return 0;
314 }
315
316
317 /* Parse the string TIMESTAMP into a time_t.  The string may either be
318    seconds since Epoch or in the ISO 8601 format like
319    "20390815T143012".  Returns 0 for an empty string or seconds since
320    Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
321    point to the next non-parsed character in TIMESTRING. */
322 time_t
323 _gpgme_parse_timestamp (const char *timestamp, char **endp)
324 {
325   /* Need to skip leading spaces, because that is what strtoul does
326      but not our ISO 8601 checking code. */
327   while (*timestamp && *timestamp== ' ')
328     timestamp++;
329   if (!*timestamp)
330     return 0;
331
332   if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
333     {
334       struct tm buf;
335       int year;
336
337       year = atoi_4 (timestamp);
338       if (year < 1900)
339         return (time_t)(-1);
340
341       /* Fixme: We would better use a configure test to see whether
342          mktime can handle dates beyond 2038. */
343       if (sizeof (time_t) <= 4 && year >= 2038)
344         return (time_t)2145914603; /* 2037-12-31 23:23:23 */
345
346       memset (&buf, 0, sizeof buf);
347       buf.tm_year = year - 1900;
348       buf.tm_mon = atoi_2 (timestamp+4) - 1; 
349       buf.tm_mday = atoi_2 (timestamp+6);
350       buf.tm_hour = atoi_2 (timestamp+9);
351       buf.tm_min = atoi_2 (timestamp+11);
352       buf.tm_sec = atoi_2 (timestamp+13);
353
354       if (endp)
355         *endp = (char*)(timestamp + 15);
356 #ifdef HAVE_TIMEGM
357       return timegm (&buf);
358 #else
359       {
360         time_t tim;
361         
362         putenv ("TZ=UTC");
363         tim = mktime (&buf);
364 #ifdef __GNUC__
365 #warning fixme: we must somehow reset TZ here.  It is not threadsafe anyway.
366 #endif
367         return tim;
368       }
369 #endif /* !HAVE_TIMEGM */
370     }
371   else
372     return (time_t)strtoul (timestamp, endp, 10);
373 }