src/platform_windows.cpp
author vb
Sun, 08 Feb 2015 15:18:48 -0500
changeset 55 0569864cb34e
parent 54 8f6b3a6b77a8
child 59 88429085f8da
permissions -rw-r--r--
unittest in main Makefile
     1 // Windows platform specifica
     2 
     3 #define WIN32_LEAN_AND_MEAN
     4 #ifndef UNICODE
     5 #define UNICODE
     6 #endif
     7 #define _WIN32_WINNT 0x0600
     8 
     9 #include <windows.h>
    10 #define _CRT_RAND_S
    11 #include <stdlib.h>
    12 #include <assert.h>
    13 #include <string>
    14 #include <stdexcept>
    15 #include "platform_windows.h"
    16 
    17 #ifndef WC_ERR_INVALID_CHARS
    18 #define WC_ERR_INVALID_CHARS      0x00000080  // error for invalid chars
    19 #endif
    20 
    21 using namespace std;
    22 
    23 static string utf8_string(wstring wstr) {
    24     string result;
    25 
    26     if (wstr.length()) {
    27         int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
    28                 wstr.c_str(), -1, NULL, 0, NULL, NULL);
    29         assert(size);
    30         if (size) {
    31             char *buf = new char[size];
    32             WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr.c_str(),
    33                     -1, buf, size, NULL, NULL);
    34             result = buf;
    35             delete[] buf;
    36         } else
    37             throw out_of_range("input wstring is not valid"
    38                     " while converting UTF-16 to UTF-8.");
    39     }
    40 
    41     return result;
    42 }
    43 
    44 static wstring utf16_string(string str) {
    45     wstring result;
    46 
    47     if (str.length()) {
    48         int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
    49                 str.c_str(), -1, NULL, 0);
    50         assert(size);
    51         if (size) {
    52             wchar_t * buf = new wchar_t[size];
    53             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1,
    54                     buf, size);
    55             result = buf;
    56             delete[] buf;
    57         } else
    58             throw out_of_range("input string is not valid"
    59                     " while converting UTF-8 to UTF-16.");
    60     }
    61 
    62     return result;
    63 }
    64 
    65 static bool readRegistryString(
    66         HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPTSTR lpResult,
    67         DWORD dwSize, LPCTSTR lpDefault
    68     )
    69 {
    70     assert(lpResult);
    71 
    72 	HKEY theKey;
    73 	DWORD type;
    74 	DWORD bytesCopied = dwSize;
    75 	HRESULT result;
    76 
    77 	result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &theKey);
    78 	if (result != ERROR_SUCCESS) {
    79 		if (lpDefault) {
    80 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    81 			return true;
    82 		}
    83 		else
    84 			return false;
    85 	}
    86 
    87 	result = RegQueryValueEx(theKey, lpValueName, NULL, &type,
    88             (LPBYTE) lpResult, &bytesCopied);
    89     if (result != ERROR_SUCCESS || (type != REG_EXPAND_SZ && type != REG_SZ)) {
    90 		if (lpDefault) {
    91 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    92 			RegCloseKey(theKey);
    93 			return true;
    94 		}
    95 		else {
    96 			RegCloseKey(theKey);
    97 			return false;
    98 		}
    99 	}
   100 
   101 	RegCloseKey(theKey);
   102 	return true;
   103 }
   104 
   105 static const DWORD PATH_BUF_SIZE = 32768;
   106 
   107 static inline string managementPath(const char *file_path, const char *file_name)
   108 {
   109     string path;
   110 	static TCHAR tPath[PATH_BUF_SIZE];
   111 
   112     DWORD length = ExpandEnvironmentStringsW(utf16_string(file_path).c_str(),
   113             tPath, PATH_BUF_SIZE);
   114 	assert(length);
   115     if (length == 0)
   116         throw bad_alloc(); // BUG: there are other errors possible beside out of memory
   117 
   118 	CreateDirectory(tPath, NULL);
   119 	DWORD error = GetLastError();
   120 	assert(error == 0 || error == ERROR_ALREADY_EXISTS);
   121 
   122 	path = utf8_string(tPath);
   123 	path += "\\";
   124 	path += file_name;
   125 
   126 	return path;
   127 }
   128 
   129 extern "C" {
   130 
   131 void *dlopen(const char *filename, int flag) {
   132 	static TCHAR path[PATH_BUF_SIZE];
   133 
   134     assert(filename);
   135 	assert(flag == RTLD_LAZY); // only lazy binding is implemented
   136 
   137     bool result = readRegistryString(HKEY_LOCAL_MACHINE,
   138             TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
   139             PATH_BUF_SIZE, NULL);
   140 	assert(result);
   141 	if (!result)
   142 		return NULL;
   143 
   144     SetDllDirectory(TEXT(""));
   145     BOOL _result = SetDllDirectory(path);
   146     assert(_result != 0);
   147     if (_result == 0)
   148         return NULL;
   149 
   150 	HMODULE module = LoadLibrary(utf16_string(filename).c_str());
   151     SetDllDirectory(NULL);
   152 	if (module == NULL)
   153 		return NULL;
   154 	else
   155 		return (void *) module;
   156 }
   157 
   158 int dlclose(void *handle) {
   159 	if (FreeLibrary((HMODULE) handle))
   160 		return 0;
   161 	else
   162 		return 1;
   163 }
   164 
   165 void *dlsym(void *handle, const char *symbol) {
   166 	return (void *) (intptr_t) GetProcAddress((HMODULE) handle, symbol);
   167 }
   168 
   169 const char *windoze_local_db(void) {
   170 	static string path;
   171 	if (path.length() == 0)
   172         path = managementPath("%LOCALAPPDATA%\\pEp", "management.db");
   173     return path.c_str();
   174 }
   175 
   176 const char *windoze_system_db(void) {
   177 	static string path;
   178 	if (path.length() == 0)
   179 		path = managementPath("%ALLUSERSPROFILE%\\pEp", "system.db");
   180     return path.c_str();
   181 }
   182 
   183 const char *gpg_conf(void)
   184 {
   185     static string path;
   186     if (path.length() == 0)
   187         path = managementPath("%APPDATA%\\gnupg", "gpg.conf");
   188     return path.c_str();
   189 }
   190 
   191 long random(void)
   192 {
   193     unsigned int r;
   194     errno_t e;
   195 
   196     assert(sizeof(unsigned int) == sizeof(long)); // this is Windoze
   197 
   198     do {
   199         e = rand_s(&r);
   200     } while (e);
   201 
   202     return (long) (r & ((1<<31)-1));
   203 }
   204 
   205 } // "C"