First take on changes to allow building with MSC for W32CE.
[gpgme.git] / src / w32-ce.c
1 /* w32-ce.h 
2    Copyright (C) 2010 g10 Code GmbH
3
4    This file is part of GPGME.
5  
6    GPGME is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10    
11    GPGME is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15    
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
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 #include "w32-ce.h"
32
33
34 /* Return a malloced string encoded in UTF-8 from the wide char input
35    string STRING.  Caller must free this value.  Returns NULL and sets
36    ERRNO on failure.  Calling this function with STRING set to NULL is
37    not defined.  */
38 char *
39 wchar_to_utf8 (const wchar_t *string)
40 {
41   int n;
42   char *result;
43
44   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
45   if (n < 0)
46     {
47       gpg_err_set_errno (EINVAL);
48       return NULL;
49     }
50
51   result = malloc (n+1);
52   if (!result)
53     return NULL;
54
55   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
56   if (n < 0)
57     {
58       free (result);
59       gpg_err_set_errno (EINVAL);
60       result = NULL;
61     }
62   return result;
63 }
64
65
66 /* Return a malloced wide char string from an UTF-8 encoded input
67    string STRING.  Caller must free this value.  Returns NULL and sets
68    ERRNO on failure.  Calling this function with STRING set to NULL is
69    not defined.  */
70 wchar_t *
71 utf8_to_wchar (const char *string)
72 {
73   int n;
74   size_t nbytes;
75   wchar_t *result;
76
77   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
78   if (n < 0)
79     {
80       gpg_err_set_errno (EINVAL);
81       return NULL;
82     }
83
84   nbytes = (size_t)(n+1) * sizeof(*result);
85   if (nbytes / sizeof(*result) != (n+1)) 
86     {
87       gpg_err_set_errno (ENOMEM);
88       return NULL;
89     }
90   result = malloc (nbytes);
91   if (!result)
92     return NULL;
93
94   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
95   if (n < 0)
96     {
97       free (result);
98       gpg_err_set_errno (EINVAL);
99       result = NULL;
100     }
101   return result;
102 }
103
104
105 #define MAX_ENV 30
106
107 char *environ[MAX_ENV + 1];
108
109 char *
110 getenv (const char *name)
111 {
112   static char *past_result;
113   char **envp;
114
115   if (past_result)
116     {
117       free (past_result);
118       past_result = NULL;
119     }
120
121 #if 0
122   if (! strcmp (name, "DBUS_VERBOSE"))
123     return past_result = get_verbose_setting ();
124   else if (! strcmp (name, "HOMEPATH"))
125     return past_result = find_my_documents_folder ();
126   else if (! strcmp (name, "DBUS_DATADIR"))
127     return past_result = find_inst_subdir ("share");
128 #endif
129
130   for (envp = environ; *envp != 0; envp++)
131     {
132       const char *varp = name;
133       char *ep = *envp;
134
135       while (*varp == *ep && *varp != '\0')
136         {
137           ++ep;
138           ++varp;
139         };
140
141       if (*varp == '\0' && *ep == '=')
142         return ep + 1;
143     }
144
145   return NULL;
146 }
147
148
149 void
150 GetSystemTimeAsFileTime (LPFILETIME ftp)
151 {
152   SYSTEMTIME st;
153   GetSystemTime (&st);
154   SystemTimeToFileTime (&st, ftp);
155 }
156
157
158 BOOL
159 DeleteFileA (LPCSTR lpFileName)
160 {
161   wchar_t *filename;
162   BOOL result;
163   int err;
164
165   filename = utf8_to_wchar (lpFileName);
166   if (!filename)
167     return FALSE;
168
169   result = DeleteFileW (filename);
170
171   err = GetLastError ();
172   free (filename);
173   SetLastError (err);
174   return result;
175 }
176
177
178 BOOL
179 CreateProcessA (LPCSTR pszImageName, LPSTR pszCmdLine,
180                 LPSECURITY_ATTRIBUTES psaProcess,
181                 LPSECURITY_ATTRIBUTES psaThread, BOOL fInheritHandles,
182                 DWORD fdwCreate, PVOID pvEnvironment, LPCSTR pszCurDir,
183                 LPSTARTUPINFOA psiStartInfo,
184                 LPPROCESS_INFORMATION pProcInfo)
185 {
186   wchar_t *image_name = NULL;
187   wchar_t *cmd_line = NULL;
188   BOOL result;
189   int err;
190
191   assert (psaProcess == NULL);
192   assert (psaThread == NULL);
193   assert (fInheritHandles == FALSE);
194   assert (pvEnvironment == NULL);
195   assert (pszCurDir == NULL);
196   /* psiStartInfo is generally not NULL.  */
197
198   if (pszImageName)
199     {
200       image_name = utf8_to_wchar (pszImageName);
201       if (!image_name)
202         return 0;
203     }
204   if (pszCmdLine)
205     {
206       cmd_line = utf8_to_wchar (pszCmdLine);
207       if (!cmd_line)
208         {
209           if (image_name)
210             free (image_name);
211           return 0;
212         }
213     }
214
215   result = CreateProcessW (image_name, cmd_line, NULL, NULL, FALSE,
216                            fdwCreate, NULL, NULL, NULL, pProcInfo);
217
218   err = GetLastError ();
219   free (image_name);
220   free (cmd_line);
221   SetLastError (err);
222   return result;
223 }
224
225
226 LONG
227 RegOpenKeyExA (HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,
228                REGSAM samDesired, PHKEY phkResult)
229 {
230   wchar_t *subkey;
231   LONG result;
232   int err;
233
234   if (lpSubKey)
235     {
236       subkey = utf8_to_wchar (lpSubKey);
237       if (!subkey)
238         return 0;
239     }
240   else
241     subkey = NULL;
242
243   result = RegOpenKeyEx (hKey, subkey, ulOptions, samDesired, phkResult);
244
245   err = GetLastError ();
246   free (subkey);
247   SetLastError (err);
248   return result;
249 }
250
251
252 LONG WINAPI
253 RegQueryValueExA (HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved,
254                   LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
255 {
256   wchar_t *name;
257   LONG err;
258   BYTE *data;
259   DWORD data_len;
260   DWORD type;
261
262   if (lpValueName)
263     {
264       name = utf8_to_wchar (lpValueName);
265       if (!name)
266         return GetLastError ();
267     }
268   else
269     name = NULL;
270
271   data_len = 0;
272   err = RegQueryValueExW (hKey, name, lpReserved, lpType, NULL, &data_len);
273   if (err || !lpcbData)
274     {
275       free (name);
276       return err;
277     }
278
279   data = malloc (data_len + sizeof (wchar_t));
280   if (!data)
281     {
282       free (name);
283       return ERROR_NOT_ENOUGH_MEMORY;
284     }
285   
286   err = RegQueryValueExW (hKey, name, lpReserved, &type, data, &data_len);
287   if (lpType)
288     *lpType = type;
289   free (name);
290   /* If err is ERROR_MORE_DATA, there probably was a race condition.
291      We can punt this to the caller just as well.  */
292   if (err)
293     return err;
294
295   /* NOTE: REG_MULTI_SZ and REG_EXPAND_SZ not supported, because they
296      are not needed in this module.  */
297   if (type == REG_SZ)
298     {
299       char *data_c;
300       int data_c_len;
301
302       /* This is valid since we allocated one more above.  */
303       data[data_len] = '\0';
304       data[data_len + 1] = '\0';
305       
306       data_c = wchar_to_utf8 ((wchar_t*) data);
307       if (!data_c)
308         return GetLastError();
309
310       data_c_len = strlen (data_c) + 1;
311       assert (data_c_len <= data_len + sizeof (wchar_t));
312       memcpy (data, data_c, data_c_len);
313       data_len = data_c_len;
314       free (data_c);
315     }
316
317   /* DATA and DATA_LEN now contain the result.  */
318   if (lpData)
319     {
320       if (data_len > *lpcbData)
321         err = ERROR_MORE_DATA;
322       else
323         memcpy (lpData, data, data_len);
324     }
325   *lpcbData = data_len;
326   return err;
327 }
328
329
330 DWORD
331 GetTempPathA (DWORD nBufferLength, LPSTR lpBuffer)
332 {
333   wchar_t dummy[1];
334   DWORD len;
335
336   len = GetTempPathW (0, dummy);
337   if (len == 0)
338     return 0;
339
340   assert (len <= MAX_PATH);
341
342   /* Better be safe than sorry.  MSDN doesn't say if len is with or
343      without terminating 0.  */
344   len++;
345
346   {
347     wchar_t *buffer_w;
348     DWORD len_w;
349     char *buffer_c;
350     DWORD len_c;
351
352     buffer_w = malloc (sizeof (wchar_t) * len);
353     if (! buffer_w)
354       return 0;
355
356     len_w = GetTempPathW (len, buffer_w);
357     /* Give up if we still can't get at it.  */
358     if (len_w == 0 || len_w >= len)
359       {
360         free (buffer_w);
361         return 0;
362       }
363
364     /* Better be really safe.  */
365     buffer_w[len_w] = '\0';
366
367     buffer_c = wchar_to_utf8 (buffer_w);
368     free (buffer_w);
369     if (! buffer_c)
370       return 0;
371
372     /* strlen is correct (not _mbstrlen), because we want storage and
373        not string length.  */
374     len_c = strlen (buffer_c) + 1;
375     if (len_c > nBufferLength)
376       return len_c;
377
378     strcpy (lpBuffer, buffer_c);
379     free (buffer_c);
380     return len_c - 1;
381   }
382 }
383
384
385 BOOL
386 SHGetSpecialFolderPathA (HWND hwndOwner, LPSTR lpszPath, int nFolder,
387                          BOOL fCreate)
388 {
389   wchar_t path[MAX_PATH];
390   char *path_c;
391   BOOL result;
392
393   path[0] = (wchar_t) 0;
394   result = SHGetSpecialFolderPathW (hwndOwner, path, nFolder, fCreate);
395   /* Note: May return false even if succeeds.  */
396
397   path[MAX_PATH - 1] = (wchar_t) 0;
398   path_c = wchar_to_utf8 (path);
399   if (! path_c)
400     return 0;
401   
402   strncpy (lpszPath, path_c, MAX_PATH);
403   free (path_c);
404   lpszPath[MAX_PATH - 1] = '\0';
405   return result;
406 }