1 // This file is under GNU General Public License 3.0
4 // Windows platform specification
6 #define WIN32_LEAN_AND_MEAN
10 #define _WIN32_WINNT 0x0600
19 #include "platform_windows.h"
20 #include "dynamic_api.h"
25 #define LOCAL_DB_FILENAME "management.db"
26 #define SYSTEM_DB_FILENAME "system.db"
27 #define KEYS_DB "keys.db"
28 #define USER_FOLDER_PATH _per_user_directory()
29 #define SYSTEM_FOLDER_PATH _per_machine_directory()
31 #ifndef WC_ERR_INVALID_CHARS
32 #define WC_ERR_INVALID_CHARS 0x00000080 // error for invalid chars
38 static string utf8_string(wstring wstr) {
42 int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
43 wstr.c_str(), -1, NULL, 0, NULL, NULL);
46 char *buf = new char[size];
47 WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr.c_str(),
48 -1, buf, size, NULL, NULL);
52 throw out_of_range("input wstring is not valid"
53 " while converting UTF-16 to UTF-8.");
59 static wstring utf16_string(string str) {
63 int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
64 str.c_str(), -1, NULL, 0);
67 wchar_t * buf = new wchar_t[size];
68 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1,
73 throw out_of_range("input string is not valid"
74 " while converting UTF-8 to UTF-16.");
80 static bool readRegistryString(
81 HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPTSTR lpResult,
82 DWORD dwSize, LPCTSTR lpDefault
89 DWORD bytesCopied = dwSize;
92 result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &theKey);
93 if (result != ERROR_SUCCESS) {
95 wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
102 result = RegQueryValueEx(theKey, lpValueName, NULL, &type,
103 (LPBYTE) lpResult, &bytesCopied);
104 if (result != ERROR_SUCCESS || (type != REG_EXPAND_SZ && type != REG_SZ)) {
106 wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
120 static const DWORD PATH_BUF_SIZE = 32768;
122 static inline string managementPath(const char *file_path, const char *file_name)
125 TCHAR tPath[PATH_BUF_SIZE];
127 DWORD length = ExpandEnvironmentStringsW(utf16_string(file_path).c_str(),
128 tPath, PATH_BUF_SIZE);
131 throw bad_alloc(); // BUG: there are other errors possible beside out of memory
133 CreateDirectory(tPath, NULL);
134 DWORD error = GetLastError();
136 path = utf8_string(tPath);
143 const char *_per_machine_directory(void)
149 TCHAR tPath[PATH_BUF_SIZE];
150 TCHAR tPath2[PATH_BUF_SIZE];
152 // Get SystemFolder Registry value and use if available
153 bool result = readRegistryString(HKEY_CURRENT_USER, TEXT("SOFTWARE\\pEp"),
154 TEXT("SystemFolder"), tPath2, PATH_BUF_SIZE, NULL);
158 // If no Registry value was found, use default
160 length = ExpandEnvironmentStringsW(utf16_string(string(PER_MACHINE_DIRECTORY)).c_str(),
161 tPath, PATH_BUF_SIZE);
164 length = ExpandEnvironmentStringsW(tPath2, tPath, PATH_BUF_SIZE);
169 throw bad_alloc(); // BUG: there are other errors possible beside out of memory
171 path = utf8_string(wstring(tPath, length));
175 const char *_per_user_directory(void)
181 TCHAR tPath[PATH_BUF_SIZE];
182 TCHAR tPath2[PATH_BUF_SIZE];
184 // Get UserFolder Registry value and use if available
185 bool result = readRegistryString(HKEY_CURRENT_USER, TEXT("SOFTWARE\\pEp"),
186 TEXT("UserFolder"), tPath2, PATH_BUF_SIZE, NULL);
190 // If no Registry value was found, use default
192 length = ExpandEnvironmentStringsW(utf16_string(string(PER_USER_DIRECTORY)).c_str(),
193 tPath, PATH_BUF_SIZE);
196 length = ExpandEnvironmentStringsW(tPath2, tPath, PATH_BUF_SIZE);
201 throw bad_alloc(); // BUG: there are other errors possible beside out of memory
203 path = utf8_string(wstring(tPath));
209 DYNAMIC_API const char *per_user_directory(void)
211 return _per_user_directory();
214 DYNAMIC_API const char *per_machine_directory(void)
216 return _per_machine_directory();
219 void *dlopen(const char *filename, int flag) {
220 static TCHAR path[PATH_BUF_SIZE];
223 assert(flag == RTLD_LAZY); // only lazy binding is implemented
225 // Look up GnuPG installation in current user scope
226 bool result = readRegistryString(HKEY_CURRENT_USER,
227 TEXT("SOFTWARE\\GnuPG"), TEXT("Install Directory"), path,
228 PATH_BUF_SIZE, NULL);
229 // If not found in current user, look up in local machine
231 result = readRegistryString(HKEY_LOCAL_MACHINE,
232 TEXT("SOFTWARE\\GnuPG"), TEXT("Install Directory"), path,
233 PATH_BUF_SIZE, NULL);
238 SetDllDirectory(TEXT(""));
239 BOOL _result = SetDllDirectory(path);
240 assert(_result != 0);
244 HMODULE module = LoadLibrary(utf16_string(filename).c_str());
246 if (module == NULL) {
247 SetDllDirectory(NULL);
249 _tcscat_s(path, TEXT("\\bin"));
251 SetDllDirectory(TEXT(""));
252 _result = SetDllDirectory(path);
253 assert(_result != 0);
257 module = LoadLibrary(utf16_string(filename).c_str());
260 SetDllDirectory(NULL);
264 return (void *) module;
267 int dlclose(void *handle) {
268 if (FreeLibrary((HMODULE) handle))
274 void *dlsym(void *handle, const char *symbol) {
275 return (void *) (intptr_t) GetProcAddress((HMODULE) handle, symbol);
278 const char *windoze_keys_db(void) {
280 if (path.length() == 0) {
281 path = managementPath(USER_FOLDER_PATH, KEYS_DB);
286 const char *windoze_local_db(void) {
288 if (path.length() == 0)
289 path = managementPath(USER_FOLDER_PATH, LOCAL_DB_FILENAME);
293 const char *windoze_system_db(void) {
295 if (path.length() == 0)
296 path = managementPath(PER_MACHINE_DIRECTORY, SYSTEM_DB_FILENAME);
305 assert(sizeof(unsigned int) == sizeof(long)); // this is Windoze
311 return (long) (r & ((1U<<31)-1));
314 char *strndup(const char *s1, size_t n)
316 char *str = (char *) calloc(n + 1, 1);
324 char *stpcpy(char *dst, const char *src)
326 for (;; ++dst, ++src) {
334 size_t strlcpy(char* dst, const char* src, size_t size) {
335 size_t retval = strlen(src);
336 size_t size_to_copy = (retval < size ? retval : size - 1);
338 // strlcpy doc says src and dst not allowed to overlap, as
339 // it's undefined. So this is acceptable:
340 memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
341 dst[size_to_copy] = '\0';
344 size_t strlcat(char* dst, const char* src, size_t size) {
345 size_t start_len = strnlen(dst, size);
346 if (start_len == size)
347 return size; // no copy, no null termination in size bytes, according to spec
349 size_t add_len = strlen(src);
350 size_t retval = start_len + add_len;
351 size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1);
353 // strlcat doc says src and dst not allowed to overlap, as
354 // it's undefined. So this is acceptable:
355 memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
356 dst[start_len + size_to_copy] = '\0';
359 char *strnstr(const char *big, const char *little, size_t len) {
360 if (big == NULL || little == NULL)
366 const char* curr_big = big;
368 size_t little_len = strlen(little);
369 size_t remaining = len;
371 const char* retval = NULL;
373 for (remaining = len; remaining >= little_len && *curr_big != '\0'; remaining--, curr_big++) {
374 // find first-char match
375 if (*curr_big != *little) {
380 const char* inner_big = retval + 1;
381 const char* curr_little = little + 1;
383 for (j = 1; j < little_len; j++, inner_big++, curr_little++) {
384 if (*inner_big != *curr_little) {
392 return (char*)retval;
395 int mkstemp(char *templ)
397 char *pathname = _mktemp(templ);
400 return _open(pathname, _O_RDWR | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
403 DYNAMIC_API time_t timegm(timestamp *timeptr)
409 time_t result = _mkgmtime((struct tm *) timeptr);
413 return (result - timeptr->tm_gmtoff);
416 void uuid_generate_random(pEpUUID out)
418 RPC_STATUS rpc_status = UuidCreate(out);
419 assert(rpc_status == RPC_S_OK);
422 int uuid_parse(char *in, pEpUUID uu)
424 unsigned char *_in = (unsigned char *) in;
425 RPC_STATUS rpc_status = UuidFromStringA(_in, uu);
426 assert(rpc_status == RPC_S_OK);
427 if (rpc_status == RPC_S_INVALID_STRING_UUID)
432 void uuid_unparse_upper(pEpUUID uu, uuid_string_t out)
434 unsigned char *_out = (unsigned char*)out;
436 RPC_STATUS rpc_status = UuidToStringA(uu, &str);
437 assert(rpc_status == RPC_S_OK);
438 if (rpc_status == RPC_S_OK) {
439 memcpy(out, str, 36);
441 RpcStringFreeA(&str);
443 else { // if (rpc_status == RPC_S_OUT_OF_MEMORY)
448 void log_output_debug(const char *title,
450 const char *description,
453 const size_t size = 256;
456 snprintf(str, size, "*** %s %s %s %s\n", title, entity, description, comment);
457 OutputDebugStringA(str);