src/platform_windows.cpp
author Edouard Tisserant <edouard@pep-project.org>
Thu, 04 May 2017 16:57:23 +0200
changeset 1750 33b2fa2368e6
parent 1513 e7f7e42385b5
child 1796 51a507ac30e0
child 1804 775bb90eccd5
permissions -rw-r--r--
ENGINE-206 disable XER content in Sync message body in DEBUG mode. Seems to be triggering unicode transcoding problem in JNI adapter leading to NULL char in message.
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 // Windows platform specification
     5 
     6 #define WIN32_LEAN_AND_MEAN
     7 #ifndef UNICODE
     8 #define UNICODE
     9 #endif
    10 #define _WIN32_WINNT 0x0600
    11 
    12 #include <windows.h>
    13 #define _CRT_RAND_S
    14 #include <stdlib.h>
    15 #include <assert.h>
    16 #include <string.h>
    17 #include <string>
    18 #include <stdexcept>
    19 #include "platform_windows.h"
    20 #include <fcntl.h>
    21 #include <sys\stat.h>
    22 
    23 #ifndef WC_ERR_INVALID_CHARS
    24 #define WC_ERR_INVALID_CHARS      0x00000080  // error for invalid chars
    25 #endif
    26 
    27 using namespace std;
    28 
    29 static string utf8_string(wstring wstr) {
    30     string result;
    31 
    32     if (wstr.length()) {
    33         int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
    34                 wstr.c_str(), -1, NULL, 0, NULL, NULL);
    35         assert(size);
    36         if (size) {
    37             char *buf = new char[size];
    38             WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr.c_str(),
    39                     -1, buf, size, NULL, NULL);
    40             result = buf;
    41             delete[] buf;
    42         } else
    43             throw out_of_range("input wstring is not valid"
    44                     " while converting UTF-16 to UTF-8.");
    45     }
    46 
    47     return result;
    48 }
    49 
    50 static wstring utf16_string(string str) {
    51     wstring result;
    52 
    53     if (str.length()) {
    54         int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
    55                 str.c_str(), -1, NULL, 0);
    56         assert(size);
    57         if (size) {
    58             wchar_t * buf = new wchar_t[size];
    59             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1,
    60                     buf, size);
    61             result = buf;
    62             delete[] buf;
    63         } else
    64             throw out_of_range("input string is not valid"
    65                     " while converting UTF-8 to UTF-16.");
    66     }
    67 
    68     return result;
    69 }
    70 
    71 static bool readRegistryString(
    72         HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPTSTR lpResult,
    73         DWORD dwSize, LPCTSTR lpDefault
    74     )
    75 {
    76     assert(lpResult);
    77 
    78 	HKEY theKey;
    79 	DWORD type;
    80 	DWORD bytesCopied = dwSize;
    81 	HRESULT result;
    82 
    83 	result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &theKey);
    84 	if (result != ERROR_SUCCESS) {
    85 		if (lpDefault) {
    86 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    87 			return true;
    88 		}
    89 		else
    90 			return false;
    91 	}
    92 
    93 	result = RegQueryValueEx(theKey, lpValueName, NULL, &type,
    94             (LPBYTE) lpResult, &bytesCopied);
    95     if (result != ERROR_SUCCESS || (type != REG_EXPAND_SZ && type != REG_SZ)) {
    96 		if (lpDefault) {
    97 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    98 			RegCloseKey(theKey);
    99 			return true;
   100 		}
   101 		else {
   102 			RegCloseKey(theKey);
   103 			return false;
   104 		}
   105 	}
   106 
   107 	RegCloseKey(theKey);
   108 	return true;
   109 }
   110 
   111 static const DWORD PATH_BUF_SIZE = 32768;
   112 
   113 static inline string managementPath(const char *file_path, const char *file_name)
   114 {
   115     string path;
   116 	static TCHAR tPath[PATH_BUF_SIZE];
   117 
   118     DWORD length = ExpandEnvironmentStringsW(utf16_string(file_path).c_str(),
   119             tPath, PATH_BUF_SIZE);
   120 	assert(length);
   121     if (length == 0)
   122         throw bad_alloc(); // BUG: there are other errors possible beside out of memory
   123 
   124 	CreateDirectory(tPath, NULL);
   125 	DWORD error = GetLastError();
   126 
   127 	path = utf8_string(tPath);
   128 	path += "\\";
   129 	path += file_name;
   130 
   131 	return path;
   132 }
   133 
   134 extern "C" {
   135 
   136 void *dlopen(const char *filename, int flag) {
   137 	static TCHAR path[PATH_BUF_SIZE];
   138 
   139     assert(filename);
   140 	assert(flag == RTLD_LAZY); // only lazy binding is implemented
   141 
   142     bool result = readRegistryString(HKEY_LOCAL_MACHINE,
   143             TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
   144             PATH_BUF_SIZE, NULL);
   145 	assert(result);
   146 	if (!result)
   147 		return NULL;
   148 
   149     SetDllDirectory(TEXT(""));
   150     BOOL _result = SetDllDirectory(path);
   151     assert(_result != 0);
   152     if (_result == 0)
   153         return NULL;
   154 
   155 	HMODULE module = LoadLibrary(utf16_string(filename).c_str());
   156     SetDllDirectory(NULL);
   157 	if (module == NULL)
   158 		return NULL;
   159 	else
   160 		return (void *) module;
   161 }
   162 
   163 int dlclose(void *handle) {
   164 	if (FreeLibrary((HMODULE) handle))
   165 		return 0;
   166 	else
   167 		return 1;
   168 }
   169 
   170 void *dlsym(void *handle, const char *symbol) {
   171 	return (void *) (intptr_t) GetProcAddress((HMODULE) handle, symbol);
   172 }
   173 
   174 const char *windoze_local_db(void) {
   175 	static string path;
   176 	if (path.length() == 0)
   177         path = managementPath("%LOCALAPPDATA%\\pEp", "management.db");
   178     return path.c_str();
   179 }
   180 
   181 const char *windoze_system_db(void) {
   182 	static string path;
   183 	if (path.length() == 0)
   184 		path = managementPath("%ALLUSERSPROFILE%\\pEp", "system.db");
   185     return path.c_str();
   186 }
   187 
   188 const char *gpg_conf(void)
   189 {
   190     static string path;
   191     if (path.length() == 0)
   192         path = managementPath("%APPDATA%\\gnupg", "gpg.conf");
   193     return path.c_str();
   194 }
   195 
   196 const char *gpg_agent_conf(void)
   197 {
   198     static string agent_path;
   199     if (agent_path.length() == 0)
   200         agent_path = managementPath("%APPDATA%\\gnupg", "gpg-agent.conf");
   201     return agent_path.c_str();
   202 }
   203 
   204 
   205 long random(void)
   206 {
   207     unsigned int r;
   208     errno_t e;
   209 
   210     assert(sizeof(unsigned int) == sizeof(long)); // this is Windoze
   211 
   212     do {
   213         e = rand_s(&r);
   214     } while (e);
   215 
   216     return (long) (r & ((1U<<31)-1));
   217 }
   218 
   219 char *strndup(const char *s1, size_t n)
   220 {
   221     char *str = (char *) calloc(n + 1, 1);
   222     if (str == NULL)
   223         return NULL;
   224 
   225     strncpy(str, s1, n);
   226     return str;
   227 }
   228 
   229 char *stpcpy(char *dst, const char *src)
   230 {
   231     for (;; ++dst, ++src) {
   232         *dst = *src;
   233         if (*dst == 0)
   234             break;
   235     }
   236     return dst;
   237 }
   238 
   239 size_t strlcpy(char* dst, const	char* src, size_t size) {
   240     size_t retval = strlen(src);
   241     size_t size_to_copy = (retval < size ? retval : size - 1);
   242     
   243     // strlcpy doc says src and dst not allowed to overlap, as
   244     // it's undefined. So this is acceptable:
   245     memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
   246     dst[size_to_copy] = '\0';
   247     return retval;
   248 }
   249 size_t strlcat(char* dst, const	char* src, size_t size) {
   250     size_t start_len = strnlen(dst, size);
   251     if (start_len == size)
   252         return size; // no copy, no null termination in size bytes, according to spec
   253     
   254     size_t add_len = strlen(src);
   255     size_t retval = start_len + add_len;
   256     size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1);
   257     
   258     // strlcat doc says src and dst not allowed to overlap, as
   259     // it's undefined. So this is acceptable:
   260     memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
   261     dst[start_len + size_to_copy] = '\0';
   262     return retval;
   263 }
   264 
   265 int mkstemp(char *templ)
   266 {
   267     char *pathname = _mktemp(templ);
   268     if (errno)
   269         return -1;
   270     return _open(pathname, _O_RDWR | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
   271 }
   272 
   273 void uuid_generate_random(pEpUUID out)
   274 {
   275     RPC_STATUS rpc_status = UuidCreate(out);
   276     assert(rpc_status == RPC_S_OK);
   277 }
   278 
   279 int uuid_parse(char *in, pEpUUID uu)
   280 {
   281     unsigned char *_in = (unsigned char *) in;
   282     RPC_STATUS rpc_status = UuidFromStringA(_in, uu);
   283     assert(rpc_status == RPC_S_OK);
   284     if (rpc_status == RPC_S_INVALID_STRING_UUID)
   285         return -1;
   286     return 0;
   287 }
   288 
   289 void uuid_unparse_upper(pEpUUID uu, uuid_string_t out)
   290 {
   291     unsigned char *_out = (unsigned char*)out;
   292     RPC_CSTR str;
   293     RPC_STATUS rpc_status = UuidToStringA(uu, &str);
   294     assert(rpc_status == RPC_S_OK);
   295     if (rpc_status == RPC_S_OK) {
   296         memcpy(out, str, 36);
   297         out[36] = 0;
   298         RpcStringFreeA(&str);
   299     }
   300     else { // if (rpc_status == RPC_S_OUT_OF_MEMORY)
   301         memset(out, 0, 37);
   302     }
   303 }
   304 
   305 time_t timegm(struct tm* tm) {
   306     return _mkgmtime(tm);
   307 }
   308 
   309 } // "C"