blob: c2bac8da93c3f347b1b95eadbf743dee13d76fed [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/browser_switcher/bho/mini_bho_util.h"
#include <shlobj.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <windows.h>
namespace util {
const char* kLogPrefixes[] = {
"[*ERROR!*] : ",
"[WARN] : ",
"[info] : ",
"[debug] : ",
};
// Points to "AppData\LocalLow\Google\BrowserSwitcher\ie_bho_log2.txt".
HANDLE g_log_file = 0;
const wchar_t* g_log_file_path_for_testing = nullptr;
void GetLogFilePath(wchar_t* log_file_path) {
if (g_log_file_path_for_testing != nullptr) {
::StringCchCopyW(log_file_path, MAX_PATH, g_log_file_path_for_testing);
return;
}
OSVERSIONINFO info = {0};
info.dwOSVersionInfoSize = sizeof(info);
GetVersionEx(&info);
if (info.dwMajorVersion >= 6) {
wchar_t* path;
// On modern Windows versions there is a special AppData folder for
// processes with lowered execution rights, however older versions lack
// this folder so be prepared to back off to the usual AppData folder.
if (S_OK !=
::SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, nullptr, &path)) {
if (S_OK !=
::SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path)) {
return;
}
}
::StringCchCopyW(log_file_path, MAX_PATH, path);
::CoTaskMemFree(path);
} else {
// Old windows version only support SHGetSpecialFolderPath.
if (!::SHGetSpecialFolderPath(0, log_file_path, CSIDL_LOCAL_APPDATA, false))
return;
}
::StringCchCatW(log_file_path, MAX_PATH, L"\\Google");
::CreateDirectory(log_file_path, nullptr);
::StringCchCatW(log_file_path, MAX_PATH, L"\\BrowserSwitcher");
::CreateDirectory(log_file_path, nullptr);
::StringCchCatW(log_file_path, MAX_PATH, L"\\ie_bho_log2.txt");
}
void InitLog() {
wchar_t log_file_path[MAX_PATH] = L"";
GetLogFilePath(log_file_path);
if (*log_file_path == '\0')
return;
g_log_file =
::CreateFile(log_file_path, GENERIC_WRITE, FILE_SHARE_READ, nullptr,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
}
void CloseLog() {
::CloseHandle(g_log_file);
}
void SetLogFilePathForTesting(const wchar_t* log_file_path) {
g_log_file_path_for_testing = log_file_path;
}
void write(const char* s, size_t num) {
if (g_log_file)
::WriteFile(g_log_file, s, num, nullptr, nullptr);
}
void vprintf(const char* fmt, va_list arglist) {
// wvsprintfA() is limited to 1024 chars. The rest is truncated.
char buffer[1025];
wvsprintfA(buffer, fmt, arglist);
write(buffer, ::lstrlenA(buffer));
}
void printf(const char* fmt, ...) {
va_list arglist;
va_start(arglist, fmt);
vprintf(fmt, arglist);
va_end(arglist);
}
void printf(LogLevel lvl, const char* fmt, ...) {
if (kLogLevel < lvl)
return;
printf("%s", kLogPrefixes[lvl]);
va_list arglist;
va_start(arglist, fmt);
vprintf(fmt, arglist);
va_end(arglist);
}
void puts(const char* s) {
printf("%s\n", s);
}
void puts(LogLevel lvl, const char* s) {
if (kLogLevel < lvl)
return;
printf("%s", kLogPrefixes[lvl]);
puts(s);
}
util::string empty_string() {
util::string empty(1);
empty[0] = '\0';
return empty;
}
util::wstring empty_wstring() {
util::wstring empty(1);
empty[0] = '\0';
return empty;
}
int max(int a, int b) {
return (a < b) ? b : a;
}
int min(int a, int b) {
return (a < b) ? a : b;
}
void* memmove(void* dest, const void* src, size_t num) {
if (dest == src)
return dest;
// Copy backwards if src < dest.
int dir = (src < dest) ? -1 : 1;
char* dest_bytes = reinterpret_cast<char*>(dest);
const char* src_bytes = reinterpret_cast<const char*>(src);
if (src < dest) {
dest_bytes += (num - 1);
src_bytes += (num - 1);
}
for (size_t i = 0; i < num; i++) {
*dest_bytes = *src_bytes;
dest_bytes += dir;
src_bytes += dir;
}
return dest;
}
char* strtok(char* str, const char* delimiters) {
static char* last_str = nullptr;
if (str == nullptr && last_str == nullptr)
return nullptr;
if (str == nullptr)
str = last_str;
size_t i = 0;
for (; ::StrChrA(delimiters, str[i]) == nullptr; i++) {
if (str[i] == '\0') {
last_str = nullptr;
return str;
}
}
str[i] = '\0';
last_str = str + i + 1;
return str;
}
bool wcs_replace_s(wchar_t* str,
size_t strsz,
const wchar_t* orig,
const wchar_t* repl) {
wchar_t* pos = ::StrStrW(str, orig);
if (pos == nullptr)
return false;
size_t str_length = ::lstrlenW(str);
size_t repl_length = ::lstrlenW(repl);
size_t orig_length = ::lstrlenW(orig);
size_t new_length = str_length + repl_length - orig_length;
wchar_t* dest = pos + repl_length;
wchar_t* src = pos + orig_length;
size_t src_length = ::lstrlenW(src);
// Move the rest of the string to the new position, making space for |repl|.
memmove(dest, src,
max(0, min(src_length, strsz - (dest - str))) * sizeof(*str));
// Insert |repl| inside the string, writing over |orig|.
memmove(pos, repl,
max(0, min(repl_length, strsz - (pos - str))) * sizeof(*str));
str[min(strsz - 1, new_length)] = '\0';
return true;
}
string utf16_to_utf8(const wchar_t* utf16) {
const size_t buffer_size = max(
1,
WideCharToMultiByte(CP_UTF8, 0, utf16, -1, nullptr, 0, nullptr, nullptr));
string utf8(buffer_size);
WideCharToMultiByte(CP_UTF8, 0, utf16, -1, utf8.data(), buffer_size, nullptr,
nullptr);
return utf8;
}
wstring utf8_to_utf16(const char* utf8) {
const size_t buffer_size =
max(1, MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0));
wstring utf16(buffer_size);
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16.data(), buffer_size);
return utf16;
}
} // namespace util