Persist the original radio name, and restore it on app start if the radio name is our radio name.

PiperOrigin-RevId: 464148898
This commit is contained in:
jfcarroll
2022-07-29 13:43:35 -07:00
committed by Copybara-Service
parent 0d4964da7b
commit 778c77eacd
20 changed files with 22492 additions and 41 deletions
+22
View File
@@ -1,3 +1,25 @@
MIT License
Copyright (c) 2013-2022 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Apache License
Version 2.0, January 2004
@@ -141,8 +141,8 @@ bool BluetoothClassic::ModifyDeviceName(const std::string& device_name) {
if (original_device_name_.empty()) {
original_device_name_ = adapter_.GetName();
}
return adapter_.SetName(device_name);
return adapter_.SetName(device_name,
/* persist= */ false);
}
bool BluetoothClassic::ModifyScanMode(ScanMode scan_mode) {
@@ -173,8 +173,8 @@ bool BluetoothClassic::RestoreScanMode() {
}
bool BluetoothClassic::RestoreDeviceName() {
if (original_device_name_.empty() ||
!adapter_.SetName(original_device_name_)) {
if (original_device_name_.empty() || !adapter_.SetName(original_device_name_,
/* persis= */ true)) {
NEARBY_LOGS(INFO) << "Failed to restore original Bluetooth device name to "
<< original_device_name_;
return false;
@@ -264,8 +264,8 @@ bool BluetoothClassic::StartAcceptingConnections(
return false;
}
BluetoothServerSocket socket = medium_.ListenForService(
service_id, GenerateUuidFromString(service_id));
BluetoothServerSocket socket =
medium_.ListenForService(service_id, GenerateUuidFromString(service_id));
if (!socket.IsValid()) {
NEARBY_LOGS(INFO) << "Failed to start accepting Bluetooth connections for "
<< service_id;
@@ -309,8 +309,7 @@ bool BluetoothClassic::IsAcceptingConnectionsLocked(
return server_sockets_.find(service_id) != server_sockets_.end();
}
bool BluetoothClassic::StopAcceptingConnections(
const std::string& service_id) {
bool BluetoothClassic::StopAcceptingConnections(const std::string& service_id) {
MutexLock lock(&mutex_);
if (service_id.empty()) {
@@ -396,9 +395,8 @@ BluetoothSocket BluetoothClassic::AttemptToConnect(
return socket;
}
socket = medium_.ConnectToService(bluetooth_device,
GenerateUuidFromString(service_id),
cancellation_flag);
socket = medium_.ConnectToService(
bluetooth_device, GenerateUuidFromString(service_id), cancellation_flag);
if (!socket.IsValid()) {
NEARBY_LOGS(INFO) << "Failed to Connect via BT [service=" << service_id
<< "]";
+13 -1
View File
@@ -21,8 +21,8 @@
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/file.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/pipe.h"
namespace location {
@@ -46,6 +46,18 @@ TEST(PayloadTest, SupportsByteArrayType) {
TEST(PayloadTest, SupportsFileType) {
constexpr size_t kOffset = 99;
const auto payload_id = Payload::GenerateId();
char test_file_data[100];
memcpy(test_file_data,
"012345678901234567890123456789012345678901234567890123456789012345678"
"901234567890123456789012345678\0",
100);
OutputFile outputFile(payload_id);
ByteArray test_data(test_file_data, 100);
outputFile.Write(test_data);
outputFile.Close();
InputFile file(payload_id, 100);
InputStream& stream = file.GetInputStream();
+12 -1
View File
@@ -163,7 +163,18 @@ class BluetoothAdapter final {
std::string GetMacAddress() const { return impl_->GetMacAddress(); }
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
bool SetName(absl::string_view name) { return impl_->SetName(name); }
bool SetName(absl::string_view name) {
// The name always persists resulting in not saving the current bluetooth
// radio name.
return impl_->SetName(name,
/* persist= */ true);
}
// If persist is set to true, we will not update the stored radio names.
// If persist is set to false, we will update the stored radio names.
bool SetName(absl::string_view name, bool persist) {
return impl_->SetName(name, persist);
}
bool IsValid() const { return impl_ != nullptr; }
+1 -1
View File
@@ -33,7 +33,7 @@ constexpr absl::string_view kId = "AB12";
class BlePeripheralStub : public api::ble_v2::BlePeripheral {
public:
explicit BlePeripheralStub(absl::string_view mac_address) {
mac_address_ = mac_address;
mac_address_ = std::string(mac_address);
}
std::string GetAddress() const override { return mac_address_; }
@@ -63,6 +63,7 @@ class BluetoothAdapter {
virtual std::string GetName() const = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
virtual bool SetName(absl::string_view name) = 0;
virtual bool SetName(absl::string_view name, bool persist) = 0;
// Returns BT MAC address assigned to this adapter.
virtual std::string GetMacAddress() const = 0;
@@ -129,6 +129,12 @@ std::string BluetoothAdapter::GetName() const {
}
bool BluetoothAdapter::SetName(absl::string_view name) {
return SetName(name,
/* persist= */ true);
}
bool BluetoothAdapter::SetName(absl::string_view name,
bool persist /*unused*/) {
BluetoothAdapter::ScanMode mode;
bool enabled;
{
@@ -120,7 +120,9 @@ class BluetoothAdapter : public api::BluetoothAdapter {
std::string GetName() const override ABSL_LOCKS_EXCLUDED(mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
bool SetName(absl::string_view name) override ABSL_LOCKS_EXCLUDED(mutex_);
bool SetName(absl::string_view) override ABSL_LOCKS_EXCLUDED(mutex_);
bool SetName(absl::string_view name, bool persist) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns BT MAC address assigned to this adapter.
std::string GetMacAddress() const override { return mac_address_; }
@@ -74,7 +74,10 @@ class BluetoothAdapter : public api::BluetoothAdapter {
ScanMode GetScanMode() const override { return mode_; }
bool SetScanMode(ScanMode mode) override { return false; }
std::string GetName() const override { return name_; }
bool SetName(absl::string_view name) override {
bool SetName(absl::string_view name) {
return SetName(name, /* persist= */ true);
}
bool SetName(absl::string_view name, bool persist) override {
name_ = std::string(name);
return true;
}
@@ -69,6 +69,8 @@ class ImplementationPlatform {
static std::string GetDownloadPath(std::string& file_name);
static std::string GetAppDataPath(absl::string_view file_name);
static OSName GetCurrentOS();
// Atomics:
@@ -16,6 +16,7 @@
#include <algorithm>
#include <cstddef>
#include <ios>
#include <memory>
#include <string>
@@ -35,9 +36,11 @@ std::unique_ptr<IOFile> IOFile::CreateInputFile(
IOFile::IOFile(const absl::string_view file_path, size_t size)
: file_(std::string(file_path.data(), file_path.size()),
std::ios::binary | std::ios::in),
std::ios::binary | std::ios::in | std::ios::ate),
path_(file_path),
total_size_(size) {}
total_size_(file_.tellg()) {
file_.seekg(0);
}
std::unique_ptr<IOFile> IOFile::CreateOutputFile(const absl::string_view path) {
return std::unique_ptr<IOFile>(new IOFile(path));
@@ -127,7 +127,7 @@ cc_library(
"wifi_lan_socket.cc",
"wifi_medium.cc",
],
copts = ["-Ithird_party/nearby/internal/platform/implementation/windows/generated"],
copts = ["-Ithird_party/nearby/internal/platform/implementation/windows/generated -Ithird_party/nearby/internal/platform/implementation/windows/json"],
defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"],
visibility = [
"//location/nearby:__subpackages__",
@@ -145,6 +145,7 @@ cc_library(
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/shared:file",
"//internal/platform/implementation/windows/generated:types",
"//internal/platform/implementation/windows/json:types",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
@@ -14,8 +14,6 @@
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include <windows.h> // These two headers must be defined
#include <winioctl.h> // first and in this order
#include <bthdef.h>
#include <bthioctl.h>
#include <cfgmgr32.h>
@@ -25,11 +23,14 @@
#include <setupapi.h>
#include <stdio.h>
#include <usbiodef.h>
#include <windows.h> // These two headers must be defined
#include <winioctl.h> // first and in this order
#include <string>
#include "absl/strings/str_format.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.h"
#include "internal/platform/implementation/windows/json/json.hpp"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/logging.h"
@@ -46,6 +47,28 @@ typedef std::basic_string<TCHAR> tstring;
namespace location {
namespace nearby {
namespace windows {
namespace {
struct LocalSettings {
std::string original_radio_name;
std::string nearby_radio_name;
};
using json = ::nlohmann::json;
constexpr absl::string_view kLocalSettingsFileName = "settings_file.json";
constexpr char kOriginalRadioName[] = "OriginalRadioName";
constexpr char kNearbyRadioName[] = "NearbyRadioName";
void to_json(json &json_output, const LocalSettings &local_settings) {
json_output = json{{kOriginalRadioName, local_settings.original_radio_name},
{kNearbyRadioName, local_settings.nearby_radio_name}};
}
void from_json(const json &json_input, LocalSettings &local_settings) {
json_input.at(kOriginalRadioName).get_to(local_settings.original_radio_name);
json_input.at(kNearbyRadioName).get_to(local_settings.nearby_radio_name);
}
} // namespace
constexpr uint8_t kAndroidDiscoverableBluetoothNameMaxLength = 37; // bytes
@@ -144,6 +167,81 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) {
return true;
}
void BluetoothAdapter::RestoreRadioNameIfNecessary() {
std::string nearby_radio_name;
std::string current_radio_name = GetName();
std::string settings_path(kLocalSettingsFileName);
auto full_path =
location::nearby::api::ImplementationPlatform::GetAppDataPath(
settings_path);
auto settings_file =
location::nearby::api::ImplementationPlatform::CreateInputFile(full_path,
0);
if (settings_file == nullptr) {
return;
}
auto total_size = settings_file->GetTotalSize();
nearby::ExceptionOr<ByteArray> raw_local_settings;
raw_local_settings = settings_file->Read(total_size);
settings_file->Close();
if (!raw_local_settings.ok()) {
return;
}
auto local_settings =
json::parse(raw_local_settings.GetResult().data(), nullptr, false);
if (local_settings.is_discarded()) {
return;
}
LocalSettings settings = local_settings.get<LocalSettings>();
if (current_radio_name == settings.nearby_radio_name) {
SetName(settings.original_radio_name,
/* persist= */ true);
}
}
void BluetoothAdapter::StoreRadioNames(absl::string_view original_radio_name,
absl::string_view nearby_radio_name) {
if (original_radio_name == nullptr || original_radio_name.size() == 0) {
return;
}
if (nearby_radio_name == nullptr || nearby_radio_name.size() == 0) {
return;
}
std::string settings_path(kLocalSettingsFileName);
auto full_path =
location::nearby::api::ImplementationPlatform::GetAppDataPath(
settings_path);
auto settings_file =
location::nearby::api::ImplementationPlatform::CreateOutputFile(
full_path);
if (settings_file == nullptr) {
return;
}
LocalSettings local_settings = {std::string(original_radio_name),
std::string(nearby_radio_name)};
json encoded_local_settings = local_settings;
ByteArray data(encoded_local_settings.dump());
settings_file->Write(data);
settings_file->Close();
}
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
// Returns an empty string on error
std::string BluetoothAdapter::GetName() const {
@@ -208,6 +306,14 @@ std::string BluetoothAdapter::GetName() const {
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
bool BluetoothAdapter::SetName(absl::string_view name) {
return SetName(name,
/* persist= */ true);
}
bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
if (!persist) {
StoreRadioNames(GetName(), name);
}
if (name.size() > 248 * sizeof(char)) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set name for bluetooth adapter because "
@@ -228,9 +334,9 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
device_name_ = std::nullopt;
if (registry_bluetooth_adapter_name_ == name) {
NEARBY_LOGS(INFO)
<< __func__
<< ": Tried to set name for bluetooth adapter to the same name again.";
NEARBY_LOGS(INFO) << __func__
<< ": Tried to set name for bluetooth adapter to the "
"same name again.";
return true;
}
@@ -302,8 +408,9 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
// lpMultiByteStr.
NULL, // // Pointer to the character to use if a character cannot be
// represented in the specified code page.
&defaultCharUsed); // // Pointer to a flag that indicates if the function
// has used a default character in the conversion.
&defaultCharUsed); // // Pointer to a flag that indicates if the
// function has used a default character in the
// conversion.
if (conversionResult == 0) {
process_error();
@@ -338,16 +445,16 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
// Creates or opens a file or I/O device.
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
hDevice = CreateFileA(
file_name
.c_str(), // The name of the file or device to be created or opened.
GENERIC_WRITE, // The requested access to the file or device.
0, // The requested sharing mode of the file or device.
NULL, // A pointer to a SECURITY_ATTRIBUTES structure.
file_name.c_str(), // The name of the file or device to be created or
// opened.
GENERIC_WRITE, // The requested access to the file or device.
0, // The requested sharing mode of the file or device.
NULL, // A pointer to a SECURITY_ATTRIBUTES structure.
OPEN_EXISTING, // An action to take on a file or device that exists or
// does not exist.
0, // The file or device attributes and flags.
NULL); // A valid handle to a template file with the GENERIC_READ access
// right. This parameter can be NULL.
NULL); // A valid handle to a template file with the GENERIC_READ
// access right. This parameter can be NULL.
if (hDevice == INVALID_HANDLE_VALUE) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to open device. Error code: "
@@ -374,8 +481,8 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
HKEY_LOCAL_MACHINE, // A handle to an open registry key.
local_name_key.c_str(), // The name of the registry subkey to be opened.
0L, // Specifies the option to apply when opening the key.
KEY_SET_VALUE, // A mask that specifies the desired access rights to the
// key to be opened.
KEY_SET_VALUE, // A mask that specifies the desired access rights to
// the key to be opened.
&hKey); // A pointer to a variable that receives a handle to the opened
// key.
@@ -391,7 +498,8 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsetvalueexa
status = RegSetValueExA(
hKey, // A handle to an open registry key
BLUETOOTH_RADIO_REGISTRY_NAME_KEY, // The name of the value to be set.
BLUETOOTH_RADIO_REGISTRY_NAME_KEY, // The name of the value to be
// set.
0, // This parameter is reserved and must be zero.
REG_BINARY, // The type of data pointed to by the lpData parameter.
(LPBYTE)std::string(name).c_str(), // The data to be stored.
@@ -436,8 +544,8 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
NULL, // A pointer to the output buffer that is to receive the data
// returned by the operation.
0, // The size of the output buffer, in bytes.
&bytes, // A pointer to a variable that receives the size of the data
// stored in the output buffer, in bytes.
&bytes, // A pointer to a variable that receives the size of the
// data stored in the output buffer, in bytes.
NULL)) { // A pointer to an OVERLAPPED structure.
NEARBY_LOGS(ERROR)
<< __func__
@@ -520,7 +628,8 @@ char *BluetoothAdapter::GetGenericBluetoothAdapterInstanceID(void) const {
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
// The SetupDiEnumDeviceInfo function returns a SP_DEVINFO_DATA structure
// that specifies a device information element in a device information set.
// that specifies a device information element in a device information
// set.
// https://docs.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdienumdeviceinfo
if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData)) break;
@@ -532,8 +641,8 @@ char *BluetoothAdapter::GetGenericBluetoothAdapterInstanceID(void) const {
if (r != CR_SUCCESS) continue;
// With Windows, a Bluetooth radio can be packaged as an external dongle or
// embedded inside a computer but it must be connected to one of the
// With Windows, a Bluetooth radio can be packaged as an external dongle
// or embedded inside a computer but it must be connected to one of the
// computer's USB ports.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/bluetooth-host-radio-support
if (strncmp("USB", deviceInstanceID, 3) == 0) {
@@ -75,6 +75,7 @@ class BluetoothAdapter : public api::BluetoothAdapter {
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
bool SetName(absl::string_view name) override;
bool SetName(absl::string_view name, bool persist) override;
// Returns BT MAC address assigned to this adapter.
std::string GetMacAddress() const override;
@@ -94,9 +95,13 @@ class BluetoothAdapter : public api::BluetoothAdapter {
// Returns true if the Bluetooth hardware supports Bluetooth 5.0 Extended
// Advertising
bool IsExtendedAdvertisingSupported() const;
void RestoreRadioNameIfNecessary();
private:
void process_error();
void StoreRadioNames(absl::string_view original_radio_name,
absl::string_view nearby_radio_name);
WindowsBluetoothAdapter windows_bluetooth_adapter_;
std::string registry_bluetooth_adapter_name_;
@@ -26,6 +26,68 @@ namespace nearby {
namespace windows {
namespace {
constexpr absl::string_view kName = "Test Radio Name";
constexpr absl::string_view kLongName =
"12345678901234567890123456789012345678";
constexpr absl::string_view kSpecialCharName = "~!@#$%^&*()_+<>:\"-}[{]";
TEST(BluetoothAdapter, DISABLED_SetNameSucceeds) {
BluetoothAdapter bluetooth_adapter;
auto original_name = bluetooth_adapter.GetName();
bluetooth_adapter.SetName(kName,
/* persist= */ false);
bluetooth_adapter.RestoreRadioNameIfNecessary();
EXPECT_EQ(bluetooth_adapter.GetName(), original_name);
}
TEST(BluetoothAdapter, DISABLED_SetNameWithTooManyChars) {
BluetoothAdapter bluetooth_adapter;
auto original_name = bluetooth_adapter.GetName();
bluetooth_adapter.SetName(kLongName,
/* persist= */ false);
auto result = bluetooth_adapter.GetName();
bluetooth_adapter.RestoreRadioNameIfNecessary();
EXPECT_EQ(result, kLongName);
EXPECT_EQ(bluetooth_adapter.GetName(), original_name);
}
TEST(BluetoothAdapter, DISABLED_SetNameWithSpecialCharsSucceeds) {
BluetoothAdapter bluetooth_adapter;
auto original_name = bluetooth_adapter.GetName();
bluetooth_adapter.SetName(kSpecialCharName,
/* persist= */ false);
auto result = bluetooth_adapter.GetName();
bluetooth_adapter.RestoreRadioNameIfNecessary();
EXPECT_EQ(result, kSpecialCharName);
EXPECT_EQ(bluetooth_adapter.GetName(), original_name);
}
TEST(BluetoothAdapter, DISABLED_SetNameWithEmptyStringSetsOriginalName) {
BluetoothAdapter bluetooth_adapter;
auto original_name = bluetooth_adapter.GetName();
bluetooth_adapter.SetName("",
/* persist= */ false);
EXPECT_EQ(bluetooth_adapter.GetName(), original_name);
}
TEST(BluetoothAdapter, DISABLED_SetNameWithNullPtrSetsOriginalName) {
BluetoothAdapter bluetooth_adapter;
auto original_name = bluetooth_adapter.GetName();
bluetooth_adapter.SetName(nullptr,
/* persist= */ false);
EXPECT_EQ(bluetooth_adapter.GetName(), original_name);
}
TEST(BluetoothAdapter, DISABLED_SetStatus) {
BluetoothAdapter bluetooth_adapter;
EXPECT_TRUE(
@@ -18,6 +18,7 @@
#include <windows.h>
#include <codecvt>
#include <fstream>
#include <locale>
#include <memory>
#include <regex> // NOLINT
@@ -50,6 +51,7 @@ BluetoothClassicMedium::BluetoothClassicMedium(
api::BluetoothAdapter& bluetoothAdapter)
: bluetooth_adapter_(dynamic_cast<BluetoothAdapter&>(bluetoothAdapter)) {
InitializeDeviceWatcher();
bluetooth_adapter_.RestoreRadioNameIfNecessary();
bluetooth_adapter_.SetOnScanModeChanged(std::bind(
&BluetoothClassicMedium::OnScanModeChanged, this, std::placeholders::_1));
@@ -33,6 +33,7 @@ cc_library(
"setupapi.lib",
"dnsapi.lib",
"wlanapi.lib",
"shlwapi.lib",
],
textual_hdrs = glob(["**/*.h"]),
visibility = [
@@ -0,0 +1,24 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
licenses(["notice"])
cc_library(
name = "types",
textual_hdrs = glob(["**/*.hpp"]),
visibility = [
"//location/nearby/cpp/sharing/implementation/internal:__subpackages__",
"//connections/windows:__subpackages__",
"//internal/platform/implementation/windows:__subpackages__",
],
)
File diff suppressed because it is too large Load Diff
@@ -14,9 +14,14 @@
#include "internal/platform/implementation/platform.h"
#include <PathCch.h>
#include <knownfolders.h>
#include <psapi.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <windows.h>
#include <winver.h>
#include <memory>
#include <sstream>
@@ -154,6 +159,7 @@ std::string CreateOutputFileWithRename(absl::string_view path) {
// While we successfully open the file, keep incrementing the count.
while (!(file.rdstate() & std::ifstream::failbit)) {
file.close();
#undef StrCat
target = absl::StrCat(folder, file_name1, " (", ++count, ")", file_name2);
file.clear();
file.open(target, std::fstream::binary | std::fstream::in);
@@ -165,6 +171,45 @@ std::string CreateOutputFileWithRename(absl::string_view path) {
return target;
}
std::string GetApplicationName(DWORD pid) {
HANDLE handle =
OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
pid); // Modify pid to the pid of your application
if (!handle) {
return "";
}
std::string szProcessName("", MAX_PATH);
DWORD len = MAX_PATH;
if (NULL != handle) {
GetModuleFileNameExA(handle, nullptr, szProcessName.data(), len);
}
szProcessName.resize(szProcessName.find_first_of('\0') + 1);
auto just_the_file_name_and_ext = szProcessName.substr(
szProcessName.find_last_of('\\') + 1,
szProcessName.length() - szProcessName.find_last_of('\\') + 1);
return just_the_file_name_and_ext.substr(
0, just_the_file_name_and_ext.find_last_of('.'));
}
bool FolderExists(const std::string& folder_name) {
DWORD ftyp = GetFileAttributesA(folder_name.c_str());
if (ftyp == INVALID_FILE_ATTRIBUTES) {
return false; // something is wrong with your path!
}
if (ftyp & FILE_ATTRIBUTE_DIRECTORY) {
return true;
} // this is a directory!
return false; // this is not a directory!
}
} // namespace
std::string ImplementationPlatform::GetDownloadPath(std::string& parent_folder,
@@ -178,6 +223,44 @@ std::string ImplementationPlatform::GetDownloadPath(std::string& file_name) {
return GetDownloadPathInternal(fake_parent_path, file_name);
}
std::string ImplementationPlatform::GetAppDataPath(
absl::string_view file_name) {
PWSTR basePath;
// Retrieves the full path of a known folder identified by the folder's
// KNOWNFOLDERID.
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
SHGetKnownFolderPath(
FOLDERID_ProgramData, // rfid: A reference to the KNOWNFOLDERID that
// identifies the folder.
0, // dwFlags: Flags that specify special retrieval options.
NULL, // hToken: An access token that represents a particular user.
&basePath); // ppszPath: When this method returns, contains the address
// of a pointer to a null-terminated Unicode string that
// specifies the path of the known folder. The calling
// process is responsible for freeing this resource once it
// is no longer needed by calling CoTaskMemFree, whether
// SHGetKnownFolderPath succeeds or not.
size_t bufferSize;
wcstombs_s(&bufferSize, NULL, 0, basePath, 0);
std::string fullpathUTF8(bufferSize - 1, '\0');
wcstombs_s(&bufferSize, fullpathUTF8.data(), bufferSize, basePath, _TRUNCATE);
CoTaskMemFree(basePath);
// Get the application image name
auto app_name = GetApplicationName(GetCurrentProcessId());
// Check if our folder exists
std::replace(fullpathUTF8.begin(), fullpathUTF8.end(), '\\', '/');
std::stringstream path("");
path << fullpathUTF8.c_str() << "/" << app_name.c_str() << "/"
<< file_name.data();
return path.str();
}
OSName ImplementationPlatform::GetCurrentOS() { return OSName::kWindows; }
std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
@@ -229,6 +312,19 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
absl::string_view file_path) {
std::string path(file_path);
std::string folder_path = path.substr(0, path.find_last_of('/'));
// Verifies that a path is a valid directory.
// https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathisdirectorya
if (!PathIsDirectoryA(folder_path.data())) {
// This function creates a file system folder whose fully qualified path is
// given by pszPath. If one or more of the intermediate folders do not
// exist, they are created as well.
// https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shcreatedirectoryexa
int result = SHCreateDirectoryExA(0, folder_path.data(), nullptr);
}
return shared::IOFile::CreateOutputFile(file_path);
}