e326bfefbb4b463951c3dd919a27128e86245456
[gpgme.git] / src / w32-ce.c
1 /* w32-ce.h
2    Copyright (C) 2010 g10 Code GmbH
3    Copyright (C) 1991,92,97,2000,02 Free Software Foundation, Inc.
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, see <https://www.gnu.org/licenses/>.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28
29 #include <gpg-error.h>
30
31 #define _WIN32_IE 0x0400 /* Required for SHGetSpecialFolderPathW.  */
32
33 /* We need to include the windows stuff here prior to shlobj.h so that
34    we get the right winsock version.  This is usually done in w32-ce.h
35    but that header also redefines some Windows functions which we need
36    to avoid unless having included shlobj.h.  */
37 #include <winsock2.h>
38 #include <ws2tcpip.h>
39 #include <windows.h>
40 #include <shlobj.h>
41
42 #include "w32-ce.h"
43
44 /* Return a malloced string encoded in UTF-8 from the wide char input
45    string STRING.  Caller must free this value.  Returns NULL and sets
46    ERRNO on failure.  Calling this function with STRING set to NULL is
47    not defined.  */
48 char *
49 wchar_to_utf8 (const wchar_t *string)
50 {
51   int n;
52   char *result;
53
54   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
55   if (n < 0)
56     {
57       gpg_err_set_errno (EINVAL);
58       return NULL;
59     }
60
61   result = malloc (n+1);
62   if (!result)
63     return NULL;
64
65   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
66   if (n < 0)
67     {
68       free (result);
69       gpg_err_set_errno (EINVAL);
70       result = NULL;
71     }
72   return result;
73 }
74
75
76 /* Return a malloced wide char string from an UTF-8 encoded input
77    string STRING.  Caller must free this value.  Returns NULL and sets
78    ERRNO on failure.  Calling this function with STRING set to NULL is
79    not defined.  */
80 wchar_t *
81 utf8_to_wchar (const char *string)
82 {
83   int n;
84   size_t nbytes;
85   wchar_t *result;
86
87   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
88   if (n < 0)
89     {
90       gpg_err_set_errno (EINVAL);
91       return NULL;
92     }
93
94   nbytes = (size_t)(n+1) * sizeof(*result);
95   if (nbytes / sizeof(*result) != (n+1))
96     {
97       gpg_err_set_errno (ENOMEM);
98       return NULL;
99     }
100   result = malloc (nbytes);
101   if (!result)
102     return NULL;
103
104   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
105   if (n < 0)
106     {
107       free (result);
108       gpg_err_set_errno (EINVAL);
109       result = NULL;
110     }
111   return result;
112 }
113
114
115 #define MAX_ENV 30
116
117 char *environ[MAX_ENV + 1];
118
119 char *
120 getenv (const char *name)
121 {
122   static char *past_result;
123   char **envp;
124
125   if (past_result)
126     {
127       free (past_result);
128       past_result = NULL;
129     }
130
131 #if 0
132   if (! strcmp (name, "DBUS_VERBOSE"))
133     return past_result = get_verbose_setting ();
134   else if (! strcmp (name, "HOMEPATH"))
135     return past_result = find_my_documents_folder ();
136   else if (! strcmp (name, "DBUS_DATADIR"))
137     return past_result = find_inst_subdir ("share");
138 #endif
139
140   for (envp = environ; *envp != 0; envp++)
141     {
142       const char *varp = name;
143       char *ep = *envp;
144
145       while (*varp == *ep && *varp != '\0')
146         {
147           ++ep;
148           ++varp;
149         };
150
151       if (*varp == '\0' && *ep == '=')
152         return ep + 1;
153     }
154
155   return NULL;
156 }
157
158
159 void
160 GetSystemTimeAsFileTime (LPFILETIME ftp)
161 {
162   SYSTEMTIME st;
163   GetSystemTime (&st);
164   SystemTimeToFileTime (&st, ftp);
165 }
166
167
168 BOOL
169 DeleteFileA (LPCSTR lpFileName)
170 {
171   wchar_t *filename;
172   BOOL result;
173   int err;
174
175   filename = utf8_to_wchar (lpFileName);
176   if (!filename)
177     return FALSE;
178
179   result = DeleteFileW (filename);
180
181   err = GetLastError ();
182   free (filename);
183   SetLastError (err);
184   return result;
185 }
186
187
188 HANDLE
189 CreateFileA (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSharedMode,
190              LPSECURITY_ATTRIBUTES lpSecurityAttributes,
191              DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
192              HANDLE hTemplateFile)
193 {
194   wchar_t *filename;
195   HANDLE result;
196   int err;
197
198   filename = utf8_to_wchar (lpFileName);
199   if (!filename)
200     return INVALID_HANDLE_VALUE;
201
202   result = CreateFileW (filename, dwDesiredAccess, dwSharedMode,
203                         lpSecurityAttributes, dwCreationDisposition,
204                         dwFlagsAndAttributes, hTemplateFile);
205
206   err = GetLastError ();
207   free (filename);
208   SetLastError (err);
209   return result;
210 }
211
212
213 BOOL
214 CreateProcessA (LPCSTR pszImageName, LPSTR pszCmdLine,
215                 LPSECURITY_ATTRIBUTES psaProcess,
216                 LPSECURITY_ATTRIBUTES psaThread, BOOL fInheritHandles,
217                 DWORD fdwCreate, PVOID pvEnvironment, LPCSTR pszCurDir,
218                 LPSTARTUPINFOA psiStartInfo,
219                 LPPROCESS_INFORMATION pProcInfo)
220 {
221   wchar_t *image_name = NULL;
222   wchar_t *cmd_line = NULL;
223   BOOL result;
224   int err;
225
226   assert (psaProcess == NULL);
227   assert (psaThread == NULL);
228   assert (fInheritHandles == FALSE);
229   assert (pvEnvironment == NULL);
230   assert (pszCurDir == NULL);
231   /* psiStartInfo is generally not NULL.  */
232
233   if (pszImageName)
234     {
235       image_name = utf8_to_wchar (pszImageName);
236       if (!image_name)
237         return 0;
238     }
239   if (pszCmdLine)
240     {
241       cmd_line = utf8_to_wchar (pszCmdLine);
242       if (!cmd_line)
243         {
244           if (image_name)
245             free (image_name);
246           return 0;
247         }
248     }
249
250   result = CreateProcessW (image_name, cmd_line, NULL, NULL, FALSE,
251                            fdwCreate, NULL, NULL, NULL, pProcInfo);
252
253   err = GetLastError ();
254   free (image_name);
255   free (cmd_line);
256   SetLastError (err);
257   return result;
258 }
259
260
261 LONG
262 RegOpenKeyExA (HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,
263                REGSAM samDesired, PHKEY phkResult)
264 {
265   wchar_t *subkey;
266   LONG result;
267   int err;
268
269   if (lpSubKey)
270     {
271       subkey = utf8_to_wchar (lpSubKey);
272       if (!subkey)
273         return 0;
274     }
275   else
276     subkey = NULL;
277
278   result = RegOpenKeyEx (hKey, subkey, ulOptions, samDesired, phkResult);
279
280   err = GetLastError ();
281   free (subkey);
282   SetLastError (err);
283   return result;
284 }
285
286
287 LONG WINAPI
288 RegQueryValueExA (HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved,
289                   LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
290 {
291   wchar_t *name;
292   LONG err;
293   void *data;
294   DWORD data_len;
295   DWORD type;
296
297   if (lpValueName)
298     {
299       name = utf8_to_wchar (lpValueName);
300       if (!name)
301         return GetLastError ();
302     }
303   else
304     name = NULL;
305
306   data_len = 0;
307   err = RegQueryValueExW (hKey, name, lpReserved, lpType, NULL, &data_len);
308   if (err || !lpcbData)
309     {
310       free (name);
311       return err;
312     }
313
314   data = malloc (data_len + sizeof (wchar_t));
315   if (!data)
316     {
317       free (name);
318       return ERROR_NOT_ENOUGH_MEMORY;
319     }
320
321   err = RegQueryValueExW (hKey, name, lpReserved, &type, data, &data_len);
322   if (lpType)
323     *lpType = type;
324   free (name);
325   /* If err is ERROR_MORE_DATA, there probably was a race condition.
326      We can punt this to the caller just as well.  */
327   if (err)
328     return err;
329
330   /* NOTE: REG_MULTI_SZ and REG_EXPAND_SZ not supported, because they
331      are not needed in this module.  */
332   if (type == REG_SZ)
333     {
334       char *data_c;
335       int data_c_len;
336
337       /* This is valid since we allocated one more above.  */
338       ((char*)data)[data_len] = '\0';
339       ((char*)data)[data_len + 1] = '\0';
340
341       data_c = wchar_to_utf8 ((wchar_t*) data);
342       if (!data_c)
343         return GetLastError();
344
345       data_c_len = strlen (data_c) + 1;
346       assert (data_c_len <= data_len + sizeof (wchar_t));
347       memcpy (data, data_c, data_c_len);
348       data_len = data_c_len;
349       free (data_c);
350     }
351
352   /* DATA and DATA_LEN now contain the result.  */
353   if (lpData)
354     {
355       if (data_len > *lpcbData)
356         err = ERROR_MORE_DATA;
357       else
358         memcpy (lpData, data, data_len);
359     }
360   *lpcbData = data_len;
361   return err;
362 }
363
364
365 DWORD
366 GetTempPathA (DWORD nBufferLength, LPSTR lpBuffer)
367 {
368   wchar_t dummy[1];
369   DWORD len;
370
371   len = GetTempPathW (0, dummy);
372   if (len == 0)
373     return 0;
374
375   assert (len <= MAX_PATH);
376
377   /* Better be safe than sorry.  MSDN doesn't say if len is with or
378      without terminating 0.  */
379   len++;
380
381   {
382     wchar_t *buffer_w;
383     DWORD len_w;
384     char *buffer_c;
385     DWORD len_c;
386
387     buffer_w = malloc (sizeof (wchar_t) * len);
388     if (! buffer_w)
389       return 0;
390
391     len_w = GetTempPathW (len, buffer_w);
392     /* Give up if we still can't get at it.  */
393     if (len_w == 0 || len_w >= len)
394       {
395         free (buffer_w);
396         return 0;
397       }
398
399     /* Better be really safe.  */
400     buffer_w[len_w] = '\0';
401
402     buffer_c = wchar_to_utf8 (buffer_w);
403     free (buffer_w);
404     if (! buffer_c)
405       return 0;
406
407     /* strlen is correct (not _mbstrlen), because we want storage and
408        not string length.  */
409     len_c = strlen (buffer_c) + 1;
410     if (len_c > nBufferLength)
411       return len_c;
412
413     strcpy (lpBuffer, buffer_c);
414     free (buffer_c);
415     return len_c - 1;
416   }
417 }
418
419
420 /* The symbol is named SHGetSpecialFolderPath and not
421    SHGetSpecialFolderPathW but shlobj.h from cegcc redefines it to *W
422    which is a bug.  Work around it.  */
423 #ifdef __MINGW32CE__
424 # undef SHGetSpecialFolderPath
425 #endif
426 BOOL
427 SHGetSpecialFolderPathA (HWND hwndOwner, LPSTR lpszPath, int nFolder,
428                          BOOL fCreate)
429 {
430   wchar_t path[MAX_PATH];
431   char *path_c;
432   BOOL result;
433
434   path[0] = (wchar_t) 0;
435   result = SHGetSpecialFolderPath (hwndOwner, path, nFolder, fCreate);
436   /* Note: May return false even if succeeds.  */
437
438   path[MAX_PATH - 1] = (wchar_t) 0;
439   path_c = wchar_to_utf8 (path);
440   if (! path_c)
441     return 0;
442
443   strncpy (lpszPath, path_c, MAX_PATH);
444   free (path_c);
445   lpszPath[MAX_PATH - 1] = '\0';
446   return result;
447 }
448
449 /* Replacement for the access function.  Note that we can't use fopen
450    here because wince might now allow to have a shared read for an
451    executable; it is better to to read the file attributes.
452
453    Limitation:  Only F_OK is supported.
454 */
455 int
456 _gpgme_wince_access (const char *fname, int mode)
457 {
458   DWORD attr;
459   wchar_t *wfname;
460
461   (void)mode;
462
463   wfname = utf8_to_wchar (fname);
464   if (!wfname)
465     return -1;
466
467   attr = GetFileAttributes (wfname);
468   free (wfname);
469   if (attr == (DWORD)(-1))
470     {
471       gpg_err_set_errno (ENOENT);
472       return -1;
473     }
474   return 0;
475 }
476
477
478 /* Perform a binary search for KEY in BASE which has NMEMB elements
479    of SIZE bytes each.  The comparisons are done by (*COMPAR)().
480    Code taken from glibc-2.6. */
481 void *
482 _gpgme_wince_bsearch (const void *key, const void *base,
483                       size_t nmemb, size_t size,
484                       int (*compar) (const void *, const void *))
485 {
486   size_t l, u, idx;
487   const void *p;
488   int comparison;
489
490   l = 0;
491   u = nmemb;
492   while (l < u)
493     {
494       idx = (l + u) / 2;
495       p = (void *) (((const char *) base) + (idx * size));
496       comparison = (*compar) (key, p);
497       if (comparison < 0)
498         u = idx;
499       else if (comparison > 0)
500         l = idx + 1;
501       else
502         return (void *) p;
503     }
504
505   return NULL;
506 }
507