#include "osutils.h" #include #ifdef __APPLE__ #include #include #include #elif defined(__unix__) #include #include #include #include #include #else #pragma warning( disable : 4091 ) #include #pragma warning( default: 4091 ) #endif #define FILE_OPEN_MODE(fm) ((fm) & 0xf) #define FILE_SHARE_MODE(fm) ((fm) & 0xf0) namespace os { static const uint8_t utf8_limits[5] = {0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; unicode_string FromUTF8(const std::string &src) { unicode_string dest; size_t pos = 0; size_t len = src.size(); while (pos < len) { uint8_t c = src[pos++]; if (c < 0x80) { dest += c; continue; } size_t val_len; for (val_len = 0; val_len < _countof(utf8_limits); val_len++) { if (c < utf8_limits[val_len]) break; } if (val_len == 0) continue; uint32_t value = c - utf8_limits[val_len - 1]; while (val_len) { if (pos == len) break; c = src[pos++]; if (c < 0x80 || c >= 0xC0) break; value <<= 6; value |= (c - 0x80); val_len--; } if (value < 0x10000) { dest += static_cast(value); } else if (value <= 0x10FFFF) { value -= 0x10000; dest += static_cast(0xD800 + (value >> 10)); dest += static_cast(0xDC00 + (value & 0x3FF)); } } return dest; } #ifdef VMP_GNU std::wstring UCS4FromUTF8(const std::string &src) { std::wstring dest; size_t pos = 0; size_t len = src.size(); while (pos < len) { uint8_t c = src[pos++]; if (c < 0x80) { dest += c; continue; } size_t val_len; for (val_len = 0; val_len < _countof(utf8_limits); val_len++) { if (c < utf8_limits[val_len]) break; } if (val_len == 0) continue; uint32_t value = c - utf8_limits[val_len - 1]; while (val_len) { if (pos == len) break; c = src[pos++]; if (c < 0x80 || c >= 0xC0) break; value <<= 6; value |= (c - 0x80); val_len--; } dest += static_cast(value); } return dest; } #endif std::string ToUTF8(const unicode_string &src) { std::string dest; size_t pos = 0; size_t len = src.size(); while (pos < len) { uint16_t c = src[pos++]; if (c < 0x80) { dest += static_cast(c); continue; } uint32_t value; if (c >= 0xD800 && c < 0xE000) { value = 0xFFFD; if (c < 0xDC00 && pos + 1 < len) { uint16_t c2 = src[pos++]; if (c2 >= 0xDC00 && c2 < 0xE000) value = 0x10000 + ((c & 0x3FF) << 10) + (c2 & 0x3FF); } } else { value = c; } size_t val_len; for (val_len = 1; val_len < 5; val_len++) { if (value < (static_cast(1) << (val_len * 5 + 6))) break; } dest += static_cast(utf8_limits[val_len - 1] + (value >> (6 * val_len))); while (val_len) { val_len--; dest += static_cast(0x80 + ((value >> (6 * val_len)) & 0x3F)); } } return dest; } unicode_string StringToFileName(const char *name) { unicode_string res = FromUTF8(name); for (size_t i = 0; i < res.size(); i++) { if (res[i] == L'/') res[i] = L'\\'; } return res; } bool is_separator(char c) { return c == '/' #ifndef VMP_GNU || c == '\\' #endif ; } static const char *GetFileName(const char *name) { const char *res = name; while (*name) { if ((is_separator(name[0]) #ifndef VMP_GNU || name[0] == ':' #endif ) && !is_separator(name[1])) res = name + 1; name++; } return res; } static const char *GetFileExt(const char *name) { name = GetFileName(name); const char *res = NULL; while (*name) { if (*name == ' ') res = NULL; else if (*name == '.') res = name; name++; } return res ? res : name; } std::string ExtractFilePath(const char *name) { if (!name) return std::string(); return std::string(name, static_cast(GetFileName(name) - name)); } std::string ExtractFileName(const char *name) { if (!name) return std::string(); return std::string(GetFileName(name)); } std::string ExtractFileExt(const char *name) { if (!name) return std::string(); return std::string(GetFileExt(name)); } std::string ChangeFileExt(const char *name, const char *ext) { if (!name) return std::string(); std::string res = std::string(name, static_cast(GetFileExt(name) - name)); if (ext) res += ext; return res; } static bool IsRelative(const char *name) { if (name && (is_separator(*name) #ifndef VMP_GNU || (name[0] && name[1] == ':') #endif )) return false; return true; } std::string CombinePaths(const char *path, const char *file_name) { if (!path || *path == 0 || !IsRelative(file_name)) return std::string(file_name ? file_name : ""); std::string res = path; if (!res.empty()) { #ifdef VMP_GNU if (!is_separator(*(res.end() - 1))) res += '/'; #else if (!is_separator(res.back())) res += '\\'; #endif } return res + file_name; } std::string SubtractPath(const char *path, const char *file_name) { if (!path || *path == 0 || !file_name || IsRelative(file_name)) return std::string(file_name ? file_name : ""); const char *name = file_name; while (*name) { char p = *path++; char f = *name++; if (p != f) { if (is_separator(f) && is_separator(p)) continue; if (p == 0) return std::string(is_separator(f) ? name : name - 1); break; } } return std::string(file_name); } std::string GetCurrentPath() { #ifdef VMP_GNU char buff[PATH_MAX]; if (!getcwd(buff, sizeof(buff))) buff[0] = 0; return std::string(buff); #else wchar_t buff[MAX_PATH]; DWORD size = GetCurrentDirectoryW(_countof(buff), buff); return ToUTF8(std::wstring(buff, size)); #endif } std::string GetExecutablePath() { std::string res; #ifdef __APPLE__ CFURLRef url = CFBundleCopyExecutableURL(CFBundleGetMainBundle()); if (url) { CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); if (path) { char buffer[PATH_MAX]; if (CFStringGetCString(path, buffer, sizeof(buffer), kCFStringEncodingUTF8)) res = ExtractFilePath(buffer); CFRelease(path); } CFRelease(url); } #elif defined(__unix__) char buff[PATH_MAX]; ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1); if (len != -1) { buff[len] = '\0'; res = ExtractFilePath(buff); } #else wchar_t buff[MAX_PATH]; DWORD size = GetModuleFileNameW(NULL, buff, _countof(buff)); res = ExtractFilePath(ToUTF8(std::wstring(buff, size)).c_str()); #endif return res; } bool FileExists(const char *name) { if (!name) return false; #ifdef VMP_GNU struct stat s; int res = stat(name, &s); if (res == -1) return false; return true; #else return GetFileAttributesW(FromUTF8(name).c_str()) != INVALID_FILE_ATTRIBUTES; #endif } bool FileDelete(const char *name, bool toRecycleBin /*= false*/) { #ifdef VMP_GNU if(toRecycleBin) { #ifdef __APPLE__ if (0 == FSPathMoveObjectToTrashSync(name, NULL, kFSFileOperationDefaultOptions)) return true; #elif defined(__unix__) //using trash from apt-get install trash-cli system((std::string("trash \"") + name + "\"").c_str()); if (!FileExists(name)) return true; #endif } return (remove(name) == 0); #else unicode_string uname = FromUTF8(name); if(toRecycleBin) { SHFILEOPSTRUCTW operation = SHFILEOPSTRUCTW(); operation.wFunc = FO_DELETE; wchar_t full_path[MAX_PATH + 1]; DWORD lengNoTerm = GetFullPathNameW(uname.c_str(), MAX_PATH, full_path, NULL); if(lengNoTerm < MAX_PATH) { full_path[lengNoTerm + 1] = 0; //double terminated operation.pFrom = full_path; operation.fFlags = FOF_ALLOWUNDO | FOF_NO_UI; if(SHFileOperationW(&operation) == 0) return true; } } return (DeleteFileW(uname.c_str()) != FALSE); #endif } bool FileCopy(const char *src, const char *dest) { #ifdef __APPLE__ return (copyfile(src, dest, NULL, COPYFILE_ALL) == 0); #elif defined (__unix__) try { std::ifstream source(src, std::ios::binary); if (!source.is_open()) return false; std::ofstream destination(dest, std::ios::binary); if (!destination.is_open()) return false; destination << source.rdbuf(); return true; } catch(std::ios_base::failure &) { FileDelete(dest); return false; } #else return (CopyFileW(FromUTF8(src).c_str(), FromUTF8(dest).c_str(), false) != FALSE); #endif } // fmCreate Create a file with the given name. If a file with the given name exists, open the file in write mode. // fmOpenRead Open the file for reading only. // fmOpenWrite Open the file for writing only. Writing to the file completely replaces the current contents. // fmOpenReadWrite Open the file to modify the current contents rather than replace them. HANDLE FileCreate(const char *name, uint32_t mode) { #ifdef VMP_GNU int flags; switch (FILE_OPEN_MODE(mode)) { case fmOpenRead: flags = O_RDONLY; break; case fmOpenWrite: flags = O_WRONLY | O_TRUNC; break; case fmOpenReadWrite: flags = O_RDWR; break; default: return INVALID_HANDLE_VALUE; } if (mode & fmCreate) flags |= (O_CREAT | O_TRUNC); return reinterpret_cast(open(name, flags, (flags & O_CREAT) ? S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH : 0)); #else uint32_t desired_access, share_mode; switch (FILE_OPEN_MODE(mode)) { case fmOpenRead: desired_access = GENERIC_READ; break; case fmOpenWrite: desired_access = GENERIC_WRITE; break; case fmOpenReadWrite: desired_access = GENERIC_WRITE | GENERIC_READ; break; default: return INVALID_HANDLE_VALUE; } switch (FILE_SHARE_MODE(mode)) { case fmShareExclusive: share_mode = 0; break; case fmShareDenyWrite: share_mode = FILE_SHARE_READ; break; case fmShareDenyRead: share_mode = FILE_SHARE_WRITE; break; case fmShareDenyNone: share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE; break; default: return INVALID_HANDLE_VALUE; } return CreateFileW(FromUTF8(name).c_str(), desired_access, share_mode, NULL, (mode & fmCreate) ? CREATE_ALWAYS : OPEN_EXISTING, 0, NULL); #endif } bool FileClose(HANDLE h) { #ifdef VMP_GNU return (close(h) == 0); #else return (CloseHandle(h) != 0); #endif } size_t FileRead(HANDLE h, void *buf, size_t size) { #ifdef VMP_GNU size_t res; res = read(h, buf, size); #else size_t res = 0; DWORD portion; while(size > 0) { portion = (DWORD)-1; if (portion > size) portion = (DWORD)size; if (ReadFile(h, (char *)buf + res, portion, &portion, NULL) == 0) return (size_t)-1; res += portion; size -= portion; if (portion == 0) break; } #endif return res; } size_t FileWrite(HANDLE h, const void *buf, size_t size) { #ifdef VMP_GNU size_t res; res = write(h, buf, size); #else size_t res = 0; DWORD portion; while(size > 0) { portion = (DWORD)-1; if (portion > size) portion = (DWORD)size; if (WriteFile(h, (const char *)buf + res, portion, &portion, NULL) == 0) return (size_t)-1; res += portion; size -= portion; if (portion == 0) break; } #endif return res; } uint64_t FileSeek(HANDLE h, uint64_t offset, SeekOrigin origin) { uint64_t res; #ifdef VMP_GNU int method; switch (origin) { case soBeginning: method = SEEK_SET; break; case soCurrent: method = SEEK_CUR; break; case soEnd: method = SEEK_END; break; default: return -1; } res = lseek(h, offset, method); #else uint32_t method; switch (origin) { case soBeginning: method = FILE_BEGIN; break; case soCurrent: method = FILE_CURRENT; break; case soEnd: method = FILE_END; break; default: return -1; } uint32_t pos_low = static_cast(offset); uint32_t pos_high = static_cast(offset >> 32); pos_low = SetFilePointer(h, pos_low, (PLONG)&pos_high, method); if (pos_low == INVALID_SET_FILE_POINTER && GetLastError() != 0) return -1; res = (static_cast(pos_high) << 32) | pos_low; #endif return res; } bool FileSetEnd(HANDLE h) { #ifdef VMP_GNU uint64_t pos = lseek(h, 0, SEEK_CUR); if (pos == (uint64_t)-1) return false; return (ftruncate(h, pos) == 0); #else return (SetEndOfFile(h) != 0); #endif } bool FileGetCheckSum(const char *file_name, uint32_t *check_sum) { if (!file_name) return false; bool res = false; HANDLE file_handle = FileCreate(file_name, fmOpenRead | fmShareDenyNone); if (file_handle != INVALID_HANDLE_VALUE) { #ifdef VMP_GNU size_t file_size = lseek(file_handle, 0, SEEK_END); #else uint32_t file_size = GetFileSize(file_handle, NULL); HANDLE file_map = CreateFileMappingW(file_handle, NULL, PAGE_READONLY, 0, 0, NULL); if (file_map) { #endif #ifdef VMP_GNU uint16_t *file_view = reinterpret_cast(mmap(0, file_size, PROT_READ, MAP_SHARED, file_handle, 0)); if (file_view != MAP_FAILED) { #else uint16_t *file_view = static_cast(MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0)); if (file_view) { #endif bool is_valid_format = false; uint32_t header_sum = 0; IMAGE_DOS_HEADER *dos_header = reinterpret_cast(file_view); if (dos_header->e_magic == IMAGE_DOS_SIGNATURE) { IMAGE_NT_HEADERS32 *header_32 = reinterpret_cast(reinterpret_cast(file_view) + dos_header->e_lfanew); if (header_32->Signature == IMAGE_NT_SIGNATURE) { if (header_32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { header_sum = header_32->OptionalHeader.CheckSum; is_valid_format = true; } else if (header_32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { header_sum = reinterpret_cast(header_32)->OptionalHeader.CheckSum; is_valid_format = true; } } } if (is_valid_format) { uint32_t sum = 0; size_t c = (file_size + 1) / sizeof(uint16_t); for (size_t i = 0; i < c; i++) { sum += file_view[i]; if (HIWORD(sum)) sum = LOWORD(sum) + HIWORD(sum); } sum = static_cast(LOWORD(sum) + HIWORD(sum)); if (LOWORD(sum) >= LOWORD(header_sum)) { sum -= LOWORD(header_sum); } else { sum = ((LOWORD(sum) - LOWORD(header_sum)) & 0xFFFF) - 1; } if (LOWORD(sum) >= HIWORD(header_sum)) { sum -= HIWORD(header_sum); } else { sum = ((LOWORD(sum) - HIWORD(header_sum)) & 0xFFFF) - 1; } sum += file_size; *check_sum = sum; res = true; } #ifdef VMP_GNU munmap(file_view, file_size); #else UnmapViewOfFile(file_view); #endif #ifndef VMP_GNU } CloseHandle(file_map); #endif } #ifdef VMP_GNU close(file_handle); #else CloseHandle(file_handle); #endif } return res; } #ifndef VMP_GNU std::string ToOEM(const unicode_string &src) { std::string res; if (!src.empty()) { int size = WideCharToMultiByte(CP_OEMCP, 0, src.c_str(), (int)src.size(), NULL, 0, NULL, NULL); if (size > 0) { res.resize(size); WideCharToMultiByte(CP_OEMCP, 0, src.c_str(), (int)src.size(), &res[0], (int)res.size(), NULL, NULL); } } return res; } unicode_string FromACP(const std::string &src) { unicode_string res; if (!src.empty()) { int size = MultiByteToWideChar(CP_ACP, 0, src.c_str(), (int)src.size(), NULL, 0); if (size > 0) { res.resize(size); MultiByteToWideChar(CP_ACP, 0, src.c_str(), (int)src.size(), &res[0], (int)res.size()); } } return res; } bool ValidateUTF8(const std::string &src) { bool ret = true; if (!src.empty()) { int res = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src.c_str(), -1, NULL, NULL); if (res == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { ret = false; } } return ret; } #endif void Print(const char *text) { #ifdef VMP_GNU std::cout << text << std::flush; #else std::cout << ToOEM(FromUTF8(text)) << std::flush; #endif } std::vector CommandLine() { std::vector res; #ifdef __APPLE__ int num = *_NSGetArgc(); char **args = *_NSGetArgv(); for (int i = 0; i < num; i++) { if (args[i]) res.push_back(std::string(args[i])); } #elif defined(__unix__) FILE *cmdline = fopen("/proc/self/cmdline", "rb"); char *arg = 0; size_t size = 0; if (cmdline) { while (getdelim(&arg, &size, 0, cmdline) != -1) { res.push_back(std::string(arg)); } } free(arg); fclose(cmdline); #else int num; wchar_t **args = CommandLineToArgvW(GetCommandLineW(), &num); for (int i = 0; i < num; i++) { if (args[i]) res.push_back(ToUTF8(std::wstring(args[i]))); } #endif return res; } #ifdef VMP_GNU #define TOUPPER(x) toupper(x) static bool WildcardMatch(const char *name, const char *mask) #else #define TOUPPER(x) towupper(x) static bool WildcardMatch(const wchar_t *name, const wchar_t *mask) #endif { if (!name || !mask) return false; while (*name) { if (*mask == '*') { mask++; if (*mask == '\0') return true; while (*name) { if (WildcardMatch(name, mask)) return true; name++; } return false; } if (*mask == '?' || TOUPPER(*name) == TOUPPER(*mask)) { name++; mask++; } else { return false; } } while (*mask == '*') mask++; return (*mask == '\0'); } std::vector FindFiles(const char *name, const char *mask, bool only_directories) { std::vector res; if (!name || !mask) return res; #ifdef VMP_GNU DIR *dir; struct dirent *ent; dir = opendir(name); if (dir) { while ((ent = readdir(dir))) { if (WildcardMatch(ent->d_name, mask)) res.push_back(CombinePaths(name, ent->d_name)); } closedir(dir); } #else std::wstring unicode_mask = FromUTF8(mask); WIN32_FIND_DATAW find_data; HANDLE h = FindFirstFileW(FromUTF8(std::string(name) + "\\*").c_str(), &find_data); if (h != INVALID_HANDLE_VALUE) { do { if (wcscmp(find_data.cFileName, L".") == 0 || wcscmp(find_data.cFileName, L"..") == 0) continue; if (only_directories && ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) continue; if (!WildcardMatch(find_data.cFileName, unicode_mask.c_str())) continue; res.push_back(CombinePaths(name, ToUTF8(find_data.cFileName).c_str())); } while (FindNextFileW(h, &find_data) != 0); FindClose(h); } #endif return res; } uint32_t GetTickCount() { #ifdef __APPLE__ const int64_t one_million = 1000 * 1000; mach_timebase_info_data_t timebase_info; mach_timebase_info(&timebase_info); // mach_absolute_time() returns billionth of seconds, // so divide by one million to get milliseconds return static_cast((mach_absolute_time() * timebase_info.numer) / (one_million * timebase_info.denom)); #elif defined (__unix__) struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000 + tv.tv_usec / 1000; #else return ::GetTickCount(); #endif } #ifdef VMP_GNU static char* rstrip(char* s) { char* p = s + strlen(s); while (p > s && isspace((unsigned char)(*--p))) *p = '\0'; return s; } static char* lskip(const char* s) { while (*s && isspace((unsigned char)(*s))) s++; return (char*)s; } static char* find_char_or_comment(const char* s, char c) { int was_whitespace = 0; while (*s && *s != c && !(was_whitespace && *s == ';')) { was_whitespace = isspace((unsigned char)(*s)); s++; } return (char*)s; } static void SwapBuffer(unicode_char *buf, size_t size) { for (size_t i = 0; i < size; i++) { unicode_char c = buf[i]; buf[i] = (c >> 8) | (c << 8); } } bool ProfileString(const char *_section, const char *_key, const char *_value, char const *file_name, std::string *result) { static const uint8_t utf16_le_bom[] = {0xFF, 0xFE}; static const uint8_t utf16_be_bom[] = {0xFE, 0xFF}; static const uint8_t utf8_bom[] = {0xEF, 0xBB, 0xBF}; enum Encoding { enNone, enUTF16_le, enUTF16_be, enUTF8 }; char *start; char *end; char *section; char *name; char *value; Encoding encoding = enNone; std::stringstream stream; HANDLE file = FileCreate(file_name, fmOpenRead | fmShareDenyNone); if (file == INVALID_HANDLE_VALUE) { if (result) return false; } else { char bom[3] = {0}; FileRead(file, bom, sizeof(utf16_le_bom)); if (memcmp(bom, utf16_le_bom, sizeof(utf16_le_bom)) == 0) { encoding = enUTF16_le; } else if (memcmp(bom, utf16_be_bom, sizeof(utf16_be_bom)) == 0) { encoding = enUTF16_be; } else { FileRead(file, &bom[2], 1); if (memcmp(bom, utf8_bom, sizeof(utf8_bom)) == 0) encoding = enUTF8; } uint64_t begin_pos = (encoding == enNone) ? 0 : FileSeek(file, 0, soCurrent); uint64_t end_pos = FileSeek(file, 0, soEnd); size_t size = static_cast(end_pos - begin_pos); if (size) { FileSeek(file, begin_pos, soBeginning); uint8_t *buff = new uint8_t[size]; FileRead(file, buff, size); FileClose(file); if (encoding == enUTF16_be) SwapBuffer(reinterpret_cast(buff), size / sizeof(unicode_char)); stream.str((encoding == enUTF16_le || encoding == enUTF16_be) ? ToUTF8(unicode_string(reinterpret_cast(buff), size / sizeof(unicode_char))) : std::string(reinterpret_cast(buff), size)); delete [] buff; } FileClose(file); } bool section_found = false; bool value_saved = false; std::string line; std::vector lines; while (std::getline(stream, line)) { if (!line.empty() && *(line.end() - 1) == '\r') line.erase(line.size() - 1); if (!result) lines.push_back(line); start = &line[0]; start = lskip(rstrip(start)); if (*start == ';' || *start == '#') { /* Per Python ConfigParser, allow '#' comments at start of line */ } else if (*start == '[') { /* A "[section]" line */ end = find_char_or_comment(start + 1, ']'); if (*end == ']') { *end = '\0'; if (section_found) { if (_key) { if (result) { return false; } else if (!value_saved) { std::vector::iterator it = lines.end() - 1; if (_value) lines.insert(it, std::string(_key) + std::string("=") + std::string(_value)); else lines.erase(it); value_saved = true; } } else { if (result) return true; } } section = start + 1; section_found = (_strcmpi(section, _section) == 0); } } else if (*start && *start != ';') { /* Not a comment, must be a name[=:]value pair */ end = find_char_or_comment(start, '='); if (*end != '=') { end = find_char_or_comment(start, ':'); } if (*end == '=' || *end == ':') { *end = '\0'; name = rstrip(start); value = lskip(end + 1); end = find_char_or_comment(value, '\0'); if (*end == ';') *end = '\0'; rstrip(value); if (section_found) { if (_key) { if (_strcmpi(name, _key) == 0) { if (result) { *result = value; return true; } else if (!value_saved) { std::vector::iterator it = lines.end() - 1; if (_value) *it = std::string(name) + "=" + std::string(_value); else lines.erase(it); value_saved = true; } } } else { if (result) { *result += name; *result += '\0'; } } } } } } if (result) { return false; } else { file = FileCreate(file_name, fmCreate | fmOpenWrite | fmShareDenyNone); if (file == INVALID_HANDLE_VALUE) return false; switch (encoding) { case enUTF8: FileWrite(file, utf8_bom, sizeof(utf8_bom)); break; case enUTF16_le: FileWrite(file, utf16_le_bom, sizeof(utf16_le_bom)); break; case enUTF16_be: FileWrite(file, utf16_be_bom, sizeof(utf16_be_bom)); break; } if (!value_saved) { if (!section_found) lines.push_back(std::string("[") + std::string(_section) + std::string("]")); lines.push_back(std::string(_key) + std::string("=") + std::string(_value)); } for (size_t i = 0; i < lines.size(); i++) { std::string str = lines[i] + "\r\n"; if (encoding == enUTF16_le || encoding == enUTF16_be) { unicode_string wstr = FromUTF8(str); if (encoding == enUTF16_be) SwapBuffer(const_cast(wstr.c_str()), wstr.size()); FileWrite(file, wstr.c_str(), wstr.size() * sizeof(unicode_char)); } else { FileWrite(file, str.c_str(), str.size()); } } FileClose(file); return true; } } #endif bool WriteIniString(const char *section, const char *key, const char *value, const char *file_name) { #ifdef VMP_GNU return ProfileString(section, key, value, file_name, NULL); #else return WritePrivateProfileStringW(section ? FromUTF8(section).c_str() : NULL, key ? os::FromUTF8(key).c_str() : NULL, value ? os::FromUTF8(value).c_str() : NULL, file_name ? os::FromUTF8(file_name).c_str() : NULL ) != FALSE; #endif } std::string ReadIniString(const char *section, const char *key, const char *default_value, const char *file_name) { std::string res; #ifdef VMP_GNU if (!ProfileString(section, key, default_value, file_name, &res)) { if (default_value) res = std::string(default_value); } #else size_t buffer_size = 1024; os::unicode_char *buffer = NULL; for (;;) { delete [] buffer; buffer = new os::unicode_char[buffer_size]; uint32_t len = GetPrivateProfileStringW(section ? FromUTF8(section).c_str() : NULL, key ? FromUTF8(key).c_str() : NULL, default_value ? FromUTF8(default_value).c_str() : NULL, buffer, (DWORD)buffer_size, file_name ? FromUTF8(file_name).c_str() : NULL); if (len < buffer_size - sizeof(os::unicode_char)) { res = os::ToUTF8(os::unicode_string(buffer, len)); break; } buffer_size *= 4; } delete [] buffer; #endif return res; } HPROCESS ProcessOpen(uint32_t id) { #ifdef __APPLE__ mach_port_t task; if (task_for_pid(mach_task_self(), id, &task) != KERN_SUCCESS) return 0; return task; #elif defined(__unix__) return HPROCESS(id); #else return OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); #endif } bool ProcessClose(HPROCESS h) { #ifdef VMP_GNU // do nothing return true; #else return (CloseHandle(h) != 0); #endif } size_t ProcessRead(HPROCESS h, void *base_address, void *buf, size_t size) { #ifdef __APPLE__ mach_vm_size_t res; if (mach_vm_read_overwrite(h, (mach_vm_address_t)base_address, size, (mach_vm_address_t)buf, &res) != KERN_SUCCESS) return -1; return res; #elif defined(__unix__) struct iovec local, remote; local.iov_base = buf; local.iov_len = (int)size; remote.iov_base = base_address; local.iov_len = (int)size; ssize_t nread = process_vm_readv(reinterpret_cast(h), &local, 1, &remote, 1, 0); return (size_t)nread; #else SIZE_T res; if (ReadProcessMemory(h, base_address, buf, size, &res) == 0) return -1; return res; #endif } size_t ProcessWrite(HPROCESS h, void *base_address, const void *buf, size_t size) { #ifdef __APPLE__ if (mach_vm_write(h, (mach_vm_address_t)base_address, size, (mach_vm_address_t)buf) != KERN_SUCCESS) return -1; return size; #elif defined(__unix__) struct iovec local, remote; local.iov_base = const_cast(buf); local.iov_len = (int)size; remote.iov_base = base_address; local.iov_len = (int)size; ssize_t nwrite = process_vm_writev(reinterpret_cast(h), &local, 1, &remote, 1, 0); return (size_t)nwrite; #else SIZE_T res; if (WriteProcessMemory(h, base_address, buf, size, &res) == 0) return -1; return res; #endif } uint64_t GetLastWriteTime(const char *name) { uint64_t res = 0; HANDLE h = FileCreate(name, fmOpenRead | fmShareDenyNone); if (h != INVALID_HANDLE_VALUE) { #ifdef VMP_GNU struct stat stat_buf; if (fstat(h, &stat_buf) == 0) res = stat_buf.st_mtime; #else FILETIME file_time; if (GetFileTime(h, NULL, NULL , &file_time)) res = (static_cast(file_time.dwHighDateTime) << 32 | file_time.dwLowDateTime) / 10000000 - 11644473600; #endif FileClose(h); } return res; } std::vector EnumProcesses() { std::vector res; #ifdef __APPLE__ int err; static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; size_t length; bool done = false; kinfo_proc *processes = NULL; do { length = 0; err = sysctl(const_cast(name), (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0); if (err == -1) err = errno; if (err == 0) { processes = new kinfo_proc[length]; if (processes == NULL) err = ENOMEM; } if (err == 0) { err = sysctl(const_cast(name), (sizeof(name) / sizeof(*name)) - 1, processes, &length, NULL, 0); if (err == -1) err = errno; if (err == 0) { done = true; } else if (err == ENOMEM) { delete [] processes; processes = NULL; err = 0; } } } while (err == 0 && !done); mach_port_t task; if (err == 0 && processes) { for (size_t i = 0; i < length / sizeof(kinfo_proc); i++) { kinfo_proc *process = &processes[i]; if (task_for_pid(mach_task_self(), process->kp_proc.p_pid, &task) != KERN_SUCCESS) continue; PROCESS_ITEM item; item.id = process->kp_proc.p_pid; item.name = process->kp_proc.p_comm; res.push_back(item); } } delete [] processes; #elif defined(__unix__) struct dirent* dent; DIR* srcdir = opendir("/proc"); if (srcdir != NULL) { while((dent = readdir(srcdir)) != NULL) { struct stat st; if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) >= 0 && S_ISDIR(st.st_mode)) { PROCESS_ITEM item; item.id = atoi(dent->d_name); if (item.id == 0) continue; char path[4096]; snprintf(path, sizeof(path), "/proc/%d/maps", item.id); FILE *fmaps = fopen(path, "r"); if (fmaps) { char c; size_t read = fread(&c, 1, 1, fmaps); fclose(fmaps); if (read == 1) { snprintf(path, sizeof(path), "/proc/%d/comm", item.id); std::ifstream f(path); std::stringstream buffer; buffer << f.rdbuf(); item.name = buffer.str(); size_t endpos = item.name.find_last_not_of("\r\n"); if( std::string::npos != endpos ) item.name = item.name.substr( 0, endpos+1 ); res.push_back(item); } } } } } closedir(srcdir); #else DWORD processes[1024], needed; if (::EnumProcesses(processes, sizeof(processes), &needed)) { size_t count = needed / sizeof(DWORD); for (size_t i = 0; i < count; i++) { if (!processes[i]) continue; wchar_t process_name[MAX_PATH] = {0}; HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processes[i]); if (process) { if (GetModuleFileNameExW(process, 0, process_name, _countof(process_name))) { PROCESS_ITEM item; item.id = processes[i]; item.name = ExtractFileName(ToUTF8(process_name).c_str()); res.push_back(item); } CloseHandle(process); } } } #endif return res; } #ifdef __unix__ /* address perms offset dev inode pathname 00400000-00452000 r-xp 00000000 08:02 173521 /usr/bin/dbus-daemon 00651000-00652000 r--p 00051000 08:02 173521 /usr/bin/dbus-daemon 00652000-00655000 rw-p 00052000 08:02 173521 /usr/bin/dbus-daemon 00e03000-00e24000 rw-p 00000000 00:00 0 [heap] 00e24000-011f7000 rw-p 00000000 00:00 0 [heap] ... 35b1800000-35b1820000 r-xp 00000000 08:02 135522 /usr/lib64/ld-2.15.so 35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522 /usr/lib64/ld-2.15.so 35b1a20000-35b1a21000 rw-p 00020000 08:02 135522 /usr/lib64/ld-2.15.so 35b1a21000-35b1a22000 rw-p 00000000 00:00 0 35b1c00000-35b1dac000 r-xp 00000000 08:02 135870 /usr/lib64/libc-2.15.so 35b1dac000-35b1fac000 ---p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so 35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870 /usr/lib64/libc-2.15.so ... f2c6ff8c000-7f2c7078c000 rw-p 00000000 00:00 0 [stack:986] ... 7fffb2c0d000-7fffb2c2e000 rw-p 00000000 00:00 0 [stack] 7fffb2d48000-7fffb2d49000 r-xp 00000000 00:00 0 [vdso] */ static bool ParseMapsLine(const char *maps, int *inode, char *name, size_t cch_name, uint64_t *from, uint64_t *to, uint64_t *offset) { bool res = false; *inode = 0; *name = 0; *from = *to = *offset = 0; if ( strlen(maps) < cch_name && sscanf_s(maps, "%llx-%llx%*[ \trwxp-]%llx%*[ \t]%*d:%*d%*[ \t]%d%*[ \t]%s", from, to, offset, inode, name) == 5 && *inode != 0) { res = true; } return res; } #endif std::vector EnumModules(uint32_t process_id) { std::vector res; #ifdef __APPLE__ mach_port_t task; if (task_for_pid(mach_task_self(), process_id, &task) == KERN_SUCCESS) { struct task_dyld_info dyld_info; mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; if (task_info(task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) == KERN_SUCCESS) { if (dyld_info.all_image_info_addr != 0 && dyld_info.all_image_info_size != 0) { dyld_all_image_infos image_infos; if (ProcessRead(task, (void *)dyld_info.all_image_info_addr, &image_infos, sizeof(image_infos)) != (size_t)-1 && image_infos.infoArrayCount) { dyld_image_info *info_array = new dyld_image_info[image_infos.infoArrayCount]; if (ProcessRead(task, (void *)image_infos.infoArray, info_array, sizeof(dyld_image_info) * image_infos.infoArrayCount) != (size_t)-1) { for (size_t i = 0; i < image_infos.infoArrayCount; i++) { dyld_image_info *info = &info_array[i]; std::string name; char c; while (ProcessRead(task, (void *)(info->imageFilePath + name.size()), &c, sizeof(c)) != (size_t)-1) { if (!c) break; name += c; } MODULE_ITEM item; item.handle = (HMODULE)info->imageLoadAddress; item.name = name; res.push_back(item); } } delete [] info_array; } } } } #elif defined(__unix__) char maps[2048], name[2048]; snprintf(maps, sizeof(maps), "/proc/%d/maps", process_id); FILE *fmaps = fopen(maps, "r"); if (fmaps) { while (fgets(maps, sizeof(maps), fmaps)) { MODULE_ITEM item; int inode; uint64_t from, to, offset; if(ParseMapsLine(maps, &inode, name, sizeof(name), &from, &to, &offset)) { item.handle = reinterpret_cast(from); item.name = name; res.push_back(item); } } fclose(fmaps); } #else HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_id); if (process) { HMODULE mods[1024]; DWORD needed; if (EnumProcessModules(process, mods, sizeof(mods), &needed)) { //-V size_t count = needed / sizeof(HMODULE); for (size_t i = 0; i < count; i++) { wchar_t module_name[MAX_PATH] = {0}; if (GetModuleFileNameExW(process, mods[i], module_name, _countof(module_name))) { MODULE_ITEM item; item.handle = mods[i]; item.name = ToUTF8(module_name); res.push_back(item); } } } CloseHandle(process); } #endif return res; } bool GetModuleInformation(HANDLE process, HMODULE module, MODULE_INFO *info, size_t size) { if (size < sizeof(MODULE_INFO)) return false; #ifdef __APPLE__ uint8_t *address = static_cast(module); mach_header header; if (ProcessRead(process, address, &header, sizeof(header)) == (size_t)-1) return false; if (header.magic == MH_MAGIC) { info->address = address; address += sizeof(mach_header); uint32_t min_address = 0; uint32_t max_address = 0; for (size_t i = 0; i < header.ncmds; i++) { load_command command; if (ProcessRead(process, address, &command, sizeof(command)) == (size_t)-1) return false; if (command.cmd == LC_SEGMENT) { segment_command segment; if (ProcessRead(process, address, &segment, sizeof(segment)) == (size_t)-1) return false; if (segment.vmaddr) { if (!min_address) min_address = segment.vmaddr; if (max_address < segment.vmaddr + segment.vmsize) max_address = segment.vmaddr + segment.vmsize; } } address += command.cmdsize; } info->size = max_address - min_address; } else if (header.magic == MH_MAGIC_64) { info->address = address; address += sizeof(mach_header_64); uint64_t min_address = 0; uint64_t max_address = 0; for (size_t i = 0; i < header.ncmds; i++) { load_command command; if (ProcessRead(process, address, &command, sizeof(command)) == (size_t)-1) return false; if (command.cmd == LC_SEGMENT_64) { segment_command_64 segment; if (ProcessRead(process, address, &segment, sizeof(segment)) == (size_t)-1) return false; if (segment.vmaddr) { if (!min_address) min_address = segment.vmaddr; if (max_address < segment.vmaddr + segment.vmsize) max_address = segment.vmaddr + segment.vmsize; } } address += command.cmdsize; } info->size = static_cast(max_address - min_address); } else { return false; } return true; #elif defined(__unix__) bool ret = false; char maps[1024], name[2048]; snprintf(maps, sizeof(maps), "/proc/%d/maps", (int)process); FILE *fmaps = fopen(maps, "r"); if (fmaps) { while (fgets(maps, sizeof(maps), fmaps)) { int inode; uint64_t from, to, offset; if(ParseMapsLine(maps, &inode, name, sizeof(name), &from, &to, &offset) && reinterpret_cast(from) == module) { info->address = (void *)from; info->size = to - from; ret = true; } } fclose(fmaps); } return ret; #else MODULEINFO moduleInfo; if (!::GetModuleInformation(process, module, &moduleInfo, sizeof(moduleInfo))) return false; info->address = moduleInfo.lpBaseOfDll; info->size = moduleInfo.SizeOfImage; return true; #endif } std::string GetSysAppDataDirectory() { std::string res; #ifdef __APPLE__ FSRef ref; if (FSFindFolder(kOnAppropriateDisk, kSharedUserDataFolderType, kDontCreateFolder, &ref) == 0) { CFURLRef url_ref = CFURLCreateFromFSRef(NULL, &ref); if (url_ref) { char buffer[PATH_MAX]; if (CFURLGetFileSystemRepresentation(url_ref, true, (uint8_t*)buffer, sizeof(buffer))) res = std::string(buffer); CFRelease(url_ref); } } #elif defined(__unix__) const char *homedir; if ((homedir = getenv("HOME")) == NULL) { homedir = getpwuid(getuid())->pw_dir; } res = std::string(homedir) + "/.config"; //admin should use hard links to map this stuff to /usr/share etc #else os::unicode_char buffer[MAX_PATH]; if (SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, buffer) >= 0) res = os::ToUTF8(buffer); #endif return res; } bool DirectoryCreate(const char *name) { if (!name) return false; #ifdef VMP_GNU return (mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) == 0); #else return (CreateDirectoryW(FromUTF8(name).c_str(), NULL) != 0 || GetLastError() == ERROR_ALREADY_EXISTS); #endif } bool PathCreate(const char *name) { if (!name) return false; bool res = DirectoryCreate(name); if (!res) { const char *prev = GetFileName(name); if (prev != name && PathCreate(std::string(name, prev - name - 1).c_str())) res = DirectoryCreate(name); } return res; } #ifndef VMP_GNU struct LocaleInfo { LCID id; char iso_name[6]; }; static const LocaleInfo win_locale_info[] = { {0x0436, "af"}, {0x3801, "ar_AE"}, {0x3c01, "ar_BH"}, {0x1401, "ar_DZ"}, {0x0c01, "ar_EG"}, {0x0801, "ar_IQ"}, {0x2c01, "ar_JO"}, {0x3401, "ar_KW"}, {0x3001, "ar_LB"}, {0x1001, "ar_LY"}, {0x1801, "ar_MA"}, {0x2001, "ar_OM"}, {0x4001, "ar_QA"}, {0x0401, "ar_SA"}, {0x2801, "ar_SY"}, {0x1c01, "ar_TN"}, {0x2401, "ar_YE"}, {0x0423, "be"}, {0x0402, "bg"}, {0x0403, "ca"}, {0x0405, "cs"}, {0x0406, "da"}, {0x0407, "de"}, {0x0c07, "de_AT"}, {0x0807, "de_CH"}, {0x1407, "de_LI"}, {0x1007, "de_LU"}, {0x0408, "el"}, {0x0409, "en"}, {0x0c09, "en_AU"}, {0x2809, "en_BZ"}, {0x1009, "en_CA"}, {0x0809, "en_GB"}, {0x1809, "en_IE"}, {0x2009, "en_JM"}, {0x1409, "en_NZ"}, {0x2c09, "en_TT"}, {0x0409, "en_US"}, {0x1c09, "en_ZA"}, {0x040a, "es"}, {0x2c0a, "es_AR"}, {0x400a, "es_BO"}, {0x340a, "es_CL"}, {0x240a, "es_CO"}, {0x140a, "es_CR"}, {0x1c0a, "es_DO"}, {0x300a, "es_EC"}, {0x100a, "es_GT"}, {0x480a, "es_HN"}, {0x080a, "es_MX"}, {0x4c0a, "es_NI"}, {0x180a, "es_PA"}, {0x280a, "es_PE"}, {0x500a, "es_PR"}, {0x3c0a, "es_PY"}, {0x440a, "es_SV"}, {0x380a, "es_UY"}, {0x200a, "es_VE"}, {0x0425, "et"}, {0x042d, "eu"}, {0x0429, "fa"}, {0x040b, "fi"}, {0x0438, "fo"}, {0x040c, "fr"}, {0x080c, "fr_BE"}, {0x0c0c, "fr_CA"}, {0x100c, "fr_CH"}, {0x140c, "fr_LU"}, {0x040d, "he"}, {0x0439, "hi"}, {0x041a, "hr"}, {0x040e, "hu"}, {0x0421, "in"}, {0x040f, "is"}, {0x0410, "it"}, {0x0810, "it_CH"}, {0x0411, "ja"}, {0x0812, "ko"}, {0x0412, "ko"}, {0x0427, "lt"}, {0x0426, "lv"}, {0x042f, "mk"}, {0x043e, "ms"}, {0x0458, "mt"}, {0x0413, "nl"}, {0x0813, "nl_BE"}, {0x0814, "no"}, {0x0414, "no"}, {0x0415, "pl"}, {0x0816, "pt"}, {0x0416, "pt_BR"}, {0x0418, "ro"}, {0x0419, "ru"}, {0x041c, "sq"}, {0x081a, "sr"}, {0x0c1a, "sr"}, {0x041d, "sv"}, {0x081d, "sv_FI"}, {0x041e, "th"}, {0x041f, "tr"}, {0x0422, "uk"}, {0x0420, "ur"}, {0x042a, "vi"}, {0x0804, "zh"}, {0x0804, "zh_CN"}, {0x0c04, "zh_HK"}, {0x1004, "zh_SG"}, {0x0404, "zh_TW"} }; #endif #ifdef __unix__ struct LocaleInfo { char iso_name[3]; char int_name[32]; }; static const LocaleInfo lin_locale_info[] = { {"af", "Afrikaans"}, {"ar", "Arabic"}, {"be", "Belarusian"}, {"bg", "Bulgarian"}, {"ca", "Catalan"}, {"cs", "Czech"}, {"da", "Danish"}, {"de", "German"}, {"el", "Greek"}, {"en", "English"}, {"es", "Spanish"}, {"et", "Estonian"}, {"eu", "Basque"}, {"fa", "Farsi"}, {"fi", "Finnish"}, {"fo", "Faroese"}, {"fr", "French"}, {"he", "Hebrew"}, {"hi", "Hindi"}, {"hr", "Croatian"}, {"hu", "Hungarian"}, {"is", "Icelandic"}, {"it", "Italian"}, {"ja", "Japanese"}, {"ko", "Korean"}, {"lt", "Lithuanian"}, {"lv", "Latvian"}, {"mk", "Macedonian"}, {"ms", "Malay"}, {"mt", "Maltese"}, {"nl", "Dutch"}, {"pl", "Polish"}, {"pt", "Portuguese"}, {"ro", "Romanian"}, {"ru", "Russian"}, {"sq", "Albanian"}, {"sr", "Serbian"}, {"sv", "Swedish"}, {"th", "Thai"}, {"tr", "Turkish"}, {"uk", "Ukrainian"}, {"ur", "Urdu"}, {"vi", "Vietnamese"}, {"zh", "Chinese"}, }; #endif std::string GetLocaleName(const char *code) { if (!code) return std::string(); std::string res; #ifdef __APPLE__ CFStringRef id = CFStringCreateWithCString(NULL, code, kCFStringEncodingUTF8); CFLocaleRef loc = CFLocaleCreate(NULL, id); if (loc) { CFStringRef name = CFLocaleCopyDisplayNameForPropertyValue(loc, kCFLocaleLanguageCode, id); if (name) { CFMutableStringRef mutable_name = CFStringCreateMutableCopy(NULL, 0, name); CFStringCapitalize(mutable_name, loc); char buffer[1024]; if (CFStringGetCString(mutable_name, buffer, sizeof(buffer), kCFStringEncodingUTF8)) res = buffer; CFRelease(mutable_name); CFRelease(name); } CFRelease(loc); } CFRelease(id); #elif defined(__unix__) int begin = 0; int end = _countof(lin_locale_info); while (end - begin > 1) { int mid = (begin + end)/2; const LocaleInfo *info = lin_locale_info + mid; int cmp = strcmp(code, info->iso_name); if (cmp < 0) end = mid; else if (cmp > 0) begin = mid; else { res = info->int_name; break; } } #else LCID id = 0; int begin = 0; int end = _countof(win_locale_info); while (end - begin > 1) { int mid = (begin + end)/2; const LocaleInfo *info = win_locale_info + mid; int cmp = strcmp(code, info->iso_name); if (cmp < 0) end = mid; else if (cmp > 0) begin = mid; else { id = info->id; break; } } if (id) { os::unicode_char buffer[1024]; if (GetLocaleInfoW(id, LOCALE_SNATIVELANGNAME, buffer, sizeof(buffer))) { LCMapStringW(id, LCMAP_UPPERCASE, buffer, 1, buffer, 1); res = os::ToUTF8(os::unicode_string(buffer)); } } #endif if (res.empty()) res = code; return res; } std::string GetCurrentLocale() { std::string res; #ifdef __APPLE__ CFLocaleRef loc = CFLocaleCopyCurrent(); if (loc) { CFStringRef name = CFLocaleGetIdentifier(loc); if (name) { char buffer[1024]; if (CFStringGetCString(name, buffer, sizeof(buffer), kCFStringEncodingUTF8)) res = buffer; } CFRelease(loc); } #elif defined(__unix__) const char *lang = ::getenv("LANG"); if (lang && *lang) { while (char sym = *lang++) { if (sym == '.' || sym == '_') break; res += sym; } } else { res = "en"; } #else LCID id = GetUserDefaultLCID(); for (size_t i = 0; i < _countof(win_locale_info); i++) { if (win_locale_info[i].id == id) { res = win_locale_info[i].iso_name; break; } } #endif return res; } void GetLocalTime(SYSTEM_TIME *res) { #ifdef VMP_GNU time_t rawtime; time(&rawtime); struct tm local_tm; tm *timeinfo = localtime_r(&rawtime, &local_tm); res->year = static_cast(timeinfo->tm_year + 1900); res->month = static_cast(timeinfo->tm_mon); res->day = static_cast(timeinfo->tm_mday); #else SYSTEMTIME local_time; ::GetLocalTime(&local_time); res->year = local_time.wYear; res->month = static_cast(local_time.wMonth); res->day = static_cast(local_time.wDay); #endif } #ifndef VMP_GNU #include static const wchar_t letters[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; /* Generate a temporary file name based on TMPL. TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed does not exist at the time of the call to mkstemp. TMPL is overwritten with the result. */ int mkstemp (wchar_t *tmpl) { size_t len; wchar_t *XXXXXX; static unsigned long long value; unsigned long long random_time_bits; unsigned int count; int fd = -1; int save_errno = errno; /* A lower bound on the number of temporary files to attempt to generate. The maximum total number of temporary file names that can exist for a given template is 62**6. It should never be necessary to try all these combinations. Instead if a reasonable number of names is tried (we define reasonable as 62**3) fail to give the system administrator the chance to remove the problems. */ #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX unsigned int attempts = TMP_MAX; #else unsigned int attempts = ATTEMPTS_MIN; #endif len = wcsnlen_s (tmpl, MAX_PATH); if (len < 6 || wcsncmp (&tmpl[len - 6], L"XXXXXX", MAX_PATH)) { errno = EINVAL; return -1; } /* This is where the Xs start. */ XXXXXX = &tmpl[len - 6]; /* Get some more or less random data. */ { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return -1; } random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32) | (unsigned long long)ftNow.dwLowDateTime); } value += random_time_bits ^ (unsigned long long)GetCurrentThreadId (); for (count = 0; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = letters[v % 62]; v /= 62; XXXXXX[1] = letters[v % 62]; v /= 62; XXXXXX[2] = letters[v % 62]; v /= 62; XXXXXX[3] = letters[v % 62]; v /= 62; XXXXXX[4] = letters[v % 62]; v /= 62; XXXXXX[5] = letters[v % 62]; if (0 == _wsopen_s(&fd, tmpl, O_RDWR | O_CREAT | O_EXCL, _SH_DENYRW, _S_IREAD | _S_IWRITE) && fd >= 0) { errno = save_errno; return fd; } else if (errno != EEXIST) { return -1; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return -1; } #endif std::string GetTempFilePathName(const char *pathname_template /*=NULL*/) { std::string ret; #ifdef VMP_GNU char szTempFileName[PATH_MAX] = "/tmp/vmpXXXXXX"; if(pathname_template) strcpy_s(szTempFileName, pathname_template); int fd = mkstemp(szTempFileName); if(fd >= 0) { fchmod(fd, S_IRUSR | S_IWUSR | S_IXUSR); ret = szTempFileName; close(fd); } #else if(pathname_template) { os::unicode_string tempFileName = os::FromUTF8(pathname_template); int fd = mkstemp(const_cast(tempFileName.data())); if(fd >= 0) { ret = os::ToUTF8(tempFileName); _close(fd); } } else { wchar_t lpTempPathBuffer[MAX_PATH], szTempFileName[MAX_PATH]; DWORD dwRetVal = GetTempPathW(MAX_PATH, lpTempPathBuffer); if (dwRetVal <= MAX_PATH && (dwRetVal != 0)) { UINT uRetVal = GetTempFileNameW(lpTempPathBuffer, L"vmp", 0, szTempFileName); if (uRetVal > 0) { ret = os::ToUTF8(std::wstring(szTempFileName)); } } } #endif return ret; } std::string GetTempFilePathNameFor(const char *pathname) { std::string ret = os::GetTempFilePathName((std::string(pathname) + ".XXXXXX").c_str()); if(ret.empty()) { return os::GetTempFilePathName(); } return ret; } bool FileMove(const char *oldName, const char *newName) { #ifdef VMP_GNU return rename(oldName, newName) == 0; #else return MoveFileExW(os::FromUTF8(oldName).c_str(), os::FromUTF8(newName).c_str(), MOVEFILE_COPY_ALLOWED | // used only when different volumes MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == TRUE; #endif } #ifdef __APPLE__ std::string GetMainExeFileName(const char *file_name) { std::string res; CFStringRef cfPath = CFStringCreateWithCString(NULL, file_name, kCFStringEncodingUTF8); if (cfPath) { CFURLRef bundleURL = CFURLCreateWithFileSystemPath(NULL, cfPath, kCFURLPOSIXPathStyle, true); if (bundleURL) { CFBundleRef aBundle = CFBundleCreate(NULL, bundleURL); if (aBundle) { CFURLRef mainExecUrl = CFBundleCopyExecutableURL(aBundle); if(mainExecUrl) { CFURLRef mainExecAbsUrl = CFURLCopyAbsoluteURL(mainExecUrl); if(mainExecAbsUrl) { CFStringRef mainExec = CFURLCopyFileSystemPath(mainExecAbsUrl, kCFURLPOSIXPathStyle); if (mainExec) { char buffer[PATH_MAX]; if (CFStringGetCString(mainExec, buffer, sizeof(buffer), kCFStringEncodingUTF8)) res = buffer; CFRelease(mainExec); } CFRelease(mainExecAbsUrl); } CFRelease(mainExecUrl); } CFRelease(aBundle); } CFRelease(bundleURL); } CFRelease(cfPath); } return res; } #endif std::string CombineThisAppDataDirectory(const char *lastPathPart) { return os::CombinePaths(os::CombinePaths(os::GetSysAppDataDirectory().c_str(), "VMProtect Software/VMProtect").c_str(), lastPathPart); } HMODULE LibraryOpen(const std::string &name) { #ifdef VMP_GNU return dlopen(name.c_str(), RTLD_NOW); #else return LoadLibraryW(FromUTF8(name).c_str()); #endif } bool LibraryClose(HMODULE h) { #ifdef VMP_GNU return (dlclose(h) == 0); #else return (FreeLibrary(h) != 0); #endif } void *GetFunction(HMODULE h, const std::string &name) { #ifdef VMP_GNU return dlsym(h, name.c_str()); #else return GetProcAddress(h, name.c_str()); #endif } std::string ExpandEnvironmentVariables(const char *path) { #ifdef VMP_GNU std::string res; for (const char *p = path; *p; ) { const char *first = strchr(p, '%'); if (first) { const char *next = strchr(first + 1, '%'); if (next) { const char *var_value = getenv(std::string(first + 1, next - first - 1).c_str()); if (var_value) { res.append(p, first - p); res.append(var_value); } else { res.append(p, next + 1 - p); } p = next + 1; continue; } } res.append(p); break; } return res; #else unicode_string src = FromUTF8(path); unicode_string res; for (const unicode_char *p = src.c_str(); *p; ) { const unicode_char *first = wcschr(p, '%'); if (first) { const unicode_char *next = wcschr(first + 1, '%'); if (next) { size_t var_size; unicode_string var = unicode_string(first + 1, next - first - 1); _wgetenv_s(&var_size, NULL, 0, var.c_str()); //-V530 if (var_size) { res.append(p, first - p); unicode_char *var_value = new unicode_char[var_size]; _wgetenv_s(&var_size, var_value, var_size, var.c_str()); //-V530 res.append(var_value); delete [] var_value; } else { res.append(p, next + 1 - p); } p = next + 1; continue; } } res.append(p); break; } return ToUTF8(res); #endif } std::string GetEnvironmentVariable(const char *name) { #ifdef VMP_GNU if (const char *p = getenv(name)) return std::string(p); return std::string(); #else unicode_string var = FromUTF8(name); unicode_string res; size_t var_size; _wgetenv_s(&var_size, NULL, 0, var.c_str()); if (var_size) { unicode_char *var_value = new unicode_char[var_size]; _wgetenv_s(&var_size, var_value, var_size, var.c_str()); //-V530 res = var_value; delete[] var_value; } return ToUTF8(res); #endif } void SetEnvironmentVariable(const char *name, const char *value) { #ifdef VMP_GNU setenv(name, value, 1); #else _wputenv_s(FromUTF8(name).c_str(), FromUTF8(value).c_str()); #endif } }