From 49af1a96b6c135505614b5fbb269b48e525943bf Mon Sep 17 00:00:00 2001 From: Aaron Yu Date: Fri, 2 Dec 2022 14:37:13 -0800 Subject: [PATCH] Add SetCustomSavePath API to Nearby Connections PiperOrigin-RevId: 492563503 --- connections/core.cc | 6 +- connections/core.h | 5 + .../internal_payload_factory.cc | 12 ++- .../implementation/internal_payload_factory.h | 6 +- .../internal_payload_factory_test.cc | 18 ++-- .../implementation/mock_service_controller.h | 3 + .../mock_service_controller_router.h | 5 + .../offline_service_controller.cc | 10 ++ .../offline_service_controller.h | 2 + connections/implementation/payload_manager.cc | 9 +- connections/implementation/payload_manager.h | 3 + .../implementation/service_controller.h | 3 + .../service_controller_router.cc | 13 +++ .../service_controller_router.h | 3 + .../platform/implementation/g3/platform.cc | 11 +- .../platform/implementation/ios/platform.mm | 24 +++-- internal/platform/implementation/platform.h | 15 +-- .../implementation/windows/file_path.cc | 7 ++ .../implementation/windows/file_path.h | 100 +++++++++--------- .../implementation/windows/platform.cc | 20 ++-- 20 files changed, 193 insertions(+), 82 deletions(-) diff --git a/connections/core.cc b/connections/core.cc index 14a3d955..80c1a7d4 100644 --- a/connections/core.cc +++ b/connections/core.cc @@ -169,10 +169,12 @@ void Core::StopAllEndpoints(ResultCallback callback) { router_->StopAllEndpoints(&client_, callback); } -std::string Core::Dump() { - return client_.Dump(); +void Core::SetCustomSavePath(absl::string_view path, ResultCallback callback) { + router_->SetCustomSavePath(&client_, path, callback); } +std::string Core::Dump() { return client_.Dump(); } + } // namespace connections } // namespace nearby } // namespace location diff --git a/connections/core.h b/connections/core.h index c195a5ce..a4ca60b2 100644 --- a/connections/core.h +++ b/connections/core.h @@ -237,6 +237,11 @@ class Core { void InitiateBandwidthUpgrade(absl::string_view endpoint_id, ResultCallback callback); + // Sets a custom save path. Defaults to the download path. + // + // path - The path where the received files will be saved to. + void SetCustomSavePath(absl::string_view path, ResultCallback callback); + // Gets the local endpoint generated by Nearby Connections. std::string GetLocalEndpointId() { return client_.GetLocalEndpointId(); } diff --git a/connections/implementation/internal_payload_factory.cc b/connections/implementation/internal_payload_factory.cc index dbcf00d5..7500544f 100644 --- a/connections/implementation/internal_payload_factory.cc +++ b/connections/implementation/internal_payload_factory.cc @@ -316,18 +316,26 @@ std::unique_ptr CreateOutgoingInternalPayload( } std::string make_path(std::string& parent_folder, std::string& file_name) { + if (!parent_folder.empty()) { + return std::string(api::ImplementationPlatform::GetCustomSavePath( + parent_folder, file_name)); + } return std::string( api::ImplementationPlatform::GetDownloadPath(parent_folder, file_name)); } std::string make_path(std::string& parent_folder, int64_t id) { std::string file_name(std::to_string(id)); + if (!parent_folder.empty()) { + return std::string(api::ImplementationPlatform::GetCustomSavePath( + parent_folder, file_name)); + } return std::string( api::ImplementationPlatform::GetDownloadPath(parent_folder, file_name)); } std::unique_ptr CreateIncomingInternalPayload( - const PayloadTransferFrame& frame) { + const PayloadTransferFrame& frame, const std::string& custom_save_path) { if (frame.packet_type() != PayloadTransferFrame::DATA) { return {}; } @@ -351,7 +359,7 @@ std::unique_ptr CreateIncomingInternalPayload( } case PayloadTransferFrame::PayloadHeader::FILE: { - std::string parent_folder(""); + std::string parent_folder(custom_save_path); std::string file_name(""); std::string file_path(""); diff --git a/connections/implementation/internal_payload_factory.h b/connections/implementation/internal_payload_factory.h index abe3cb49..dc2896b2 100644 --- a/connections/implementation/internal_payload_factory.h +++ b/connections/implementation/internal_payload_factory.h @@ -15,6 +15,10 @@ #ifndef CORE_INTERNAL_INTERNAL_PAYLOAD_FACTORY_H_ #define CORE_INTERNAL_INTERNAL_PAYLOAD_FACTORY_H_ +#include + +#include + #include "connections/implementation/internal_payload.h" #include "connections/payload.h" @@ -28,7 +32,7 @@ std::unique_ptr CreateOutgoingInternalPayload(Payload payload); // Creates an InternalPayload representing an incoming Payload from a remote // endpoint. std::unique_ptr CreateIncomingInternalPayload( - const PayloadTransferFrame& frame); + const PayloadTransferFrame& frame, const std::string& custom_save_path); } // namespace connections } // namespace nearby diff --git a/connections/implementation/internal_payload_factory_test.cc b/connections/implementation/internal_payload_factory_test.cc index ff1b680f..797541c4 100644 --- a/connections/implementation/internal_payload_factory_test.cc +++ b/connections/implementation/internal_payload_factory_test.cc @@ -71,6 +71,7 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromFilePayload) { TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromByteMessage) { PayloadTransferFrame frame; + std::string path = "C:\\Downloads"; frame.set_packet_type(PayloadTransferFrame::DATA); std::int64_t payload_chunk_offset = 0; ByteArray data(kText); @@ -84,7 +85,7 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromByteMessage) { header.set_total_size(512); *frame.mutable_payload_chunk() = std::move(payload_chunk); std::unique_ptr internal_payload = - CreateIncomingInternalPayload(frame); + CreateIncomingInternalPayload(frame, path); EXPECT_NE(internal_payload, nullptr); Payload payload = internal_payload->ReleasePayload(); EXPECT_EQ(payload.AsFile(), nullptr); @@ -94,13 +95,14 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromByteMessage) { TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromStreamMessage) { PayloadTransferFrame frame; + std::string path = "C:\\Downloads"; frame.set_packet_type(PayloadTransferFrame::DATA); auto& header = *frame.mutable_payload_header(); header.set_type(PayloadTransferFrame::PayloadHeader::STREAM); header.set_id(12345); header.set_total_size(0); std::unique_ptr internal_payload = - CreateIncomingInternalPayload(frame); + CreateIncomingInternalPayload(frame, path); EXPECT_NE(internal_payload, nullptr); Payload payload = internal_payload->ReleasePayload(); EXPECT_EQ(payload.AsFile(), nullptr); @@ -111,13 +113,14 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromStreamMessage) { TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromFileMessage) { PayloadTransferFrame frame; + std::string path = "C:\\Downloads"; frame.set_packet_type(PayloadTransferFrame::DATA); auto& header = *frame.mutable_payload_header(); header.set_type(PayloadTransferFrame::PayloadHeader::FILE); header.set_id(12345); header.set_total_size(512); std::unique_ptr internal_payload = - CreateIncomingInternalPayload(frame); + CreateIncomingInternalPayload(frame, path); EXPECT_NE(internal_payload, nullptr); Payload payload = internal_payload->ReleasePayload(); EXPECT_NE(payload.AsFile(), nullptr); @@ -129,25 +132,27 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromFileMessage) { TEST(InternalPayloadFactoryTest, InternalPayloadFromFileMessageWithoutIdReturnsNullptr) { PayloadTransferFrame frame; + std::string path = "C:\\Downloads"; frame.set_packet_type(PayloadTransferFrame::DATA); auto& header = *frame.mutable_payload_header(); header.set_type(PayloadTransferFrame::PayloadHeader::FILE); header.set_total_size(512); std::unique_ptr internal_payload = - CreateIncomingInternalPayload(frame); + CreateIncomingInternalPayload(frame, path); EXPECT_EQ(internal_payload, nullptr); } TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromFileMessageWithFileNameNotSet) { PayloadTransferFrame frame; + std::string path = "C:\\Downloads"; frame.set_packet_type(PayloadTransferFrame::DATA); auto& header = *frame.mutable_payload_header(); header.set_type(PayloadTransferFrame::PayloadHeader::FILE); header.set_id(12345); header.set_total_size(512); std::unique_ptr internal_payload = - CreateIncomingInternalPayload(frame); + CreateIncomingInternalPayload(frame, path); EXPECT_NE(internal_payload, nullptr); Payload payload = internal_payload->ReleasePayload(); EXPECT_EQ(payload.GetFileName(), "12345"); @@ -155,6 +160,7 @@ TEST(InternalPayloadFactoryTest, TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromFileMessageWithFileNameSet) { PayloadTransferFrame frame; + std::string path = "C:\\Downloads"; frame.set_packet_type(PayloadTransferFrame::DATA); auto& header = *frame.mutable_payload_header(); header.set_type(PayloadTransferFrame::PayloadHeader::FILE); @@ -162,7 +168,7 @@ TEST(InternalPayloadFactoryTest, header.set_total_size(512); header.set_file_name("test.file.name"); std::unique_ptr internal_payload = - CreateIncomingInternalPayload(frame); + CreateIncomingInternalPayload(frame, path); EXPECT_NE(internal_payload, nullptr); auto test = internal_payload->GetFileName(); Payload payload = internal_payload->ReleasePayload(); diff --git a/connections/implementation/mock_service_controller.h b/connections/implementation/mock_service_controller.h index 10639253..f5799824 100644 --- a/connections/implementation/mock_service_controller.h +++ b/connections/implementation/mock_service_controller.h @@ -85,6 +85,9 @@ class MockServiceController : public ServiceController { (override)); MOCK_METHOD(void, ShutdownBwuManagerExecutors, (), (override)); + + MOCK_METHOD(void, SetCustomSavePath, + (ClientProxy * client, const std::string& path), (override)); }; } // namespace connections diff --git a/connections/implementation/mock_service_controller_router.h b/connections/implementation/mock_service_controller_router.h index f3aa0287..e8f7502f 100644 --- a/connections/implementation/mock_service_controller_router.h +++ b/connections/implementation/mock_service_controller_router.h @@ -92,6 +92,11 @@ class MockServiceControllerRouter : public ServiceControllerRouter { MOCK_METHOD(void, StopAllEndpoints, (ClientProxy * client, const ResultCallback& callback), (override)); + + MOCK_METHOD(void, SetCustomSavePath, + (ClientProxy * client, absl::string_view path, + const ResultCallback& callback), + (override)); }; } // namespace connections diff --git a/connections/implementation/offline_service_controller.cc b/connections/implementation/offline_service_controller.cc index 9e1bbf2c..ab445069 100644 --- a/connections/implementation/offline_service_controller.cc +++ b/connections/implementation/offline_service_controller.cc @@ -15,6 +15,8 @@ #include "connections/implementation/offline_service_controller.h" #include +#include +#include #include "absl/strings/str_join.h" @@ -142,6 +144,14 @@ void OfflineServiceController::DisconnectFromEndpoint( endpoint_manager_.UnregisterEndpoint(client, endpoint_id); } +void OfflineServiceController::SetCustomSavePath(ClientProxy* client, + const std::string& path) { + if (stop_) return; + NEARBY_LOGS(INFO) << "Client " << client->GetClientId() + << " requested to set custom save path: " << path; + payload_manager_.SetCustomSavePath(client, path); +} + void OfflineServiceController::ShutdownBwuManagerExecutors() { bwu_manager_.ShutdownExecutors(); } diff --git a/connections/implementation/offline_service_controller.h b/connections/implementation/offline_service_controller.h index e6f5885b..17a68a4b 100644 --- a/connections/implementation/offline_service_controller.h +++ b/connections/implementation/offline_service_controller.h @@ -77,6 +77,8 @@ class OfflineServiceController : public ServiceController { void Stop() override; + void SetCustomSavePath(ClientProxy* client, const std::string& path) override; + void ShutdownBwuManagerExecutors() override; private: diff --git a/connections/implementation/payload_manager.cc b/connections/implementation/payload_manager.cc index 26f6baec..cbb9a3c1 100644 --- a/connections/implementation/payload_manager.cc +++ b/connections/implementation/payload_manager.cc @@ -282,6 +282,7 @@ Payload::Id PayloadManager::CreateOutgoingPayload( PayloadManager::PayloadManager(EndpointManager& endpoint_manager) : endpoint_manager_(&endpoint_manager) { endpoint_manager_->RegisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER, this); + custom_save_path_ = ""; } void PayloadManager::CancelAllPayloads() { @@ -676,7 +677,8 @@ PayloadTransferFrame::PayloadChunk PayloadManager::CreatePayloadChunk( PayloadManager::PendingPayload* PayloadManager::CreateIncomingPayload( const PayloadTransferFrame& frame, const std::string& endpoint_id) { - auto internal_payload = CreateIncomingInternalPayload(frame); + auto internal_payload = + CreateIncomingInternalPayload(frame, custom_save_path_); if (!internal_payload) { return nullptr; } @@ -1191,6 +1193,11 @@ PayloadType PayloadManager::FramePayloadTypeToPayloadType( } } +void PayloadManager::SetCustomSavePath(ClientProxy* client, + const std::string& path) { + custom_save_path_ = path; +} + ///////////////////////////////// EndpointInfo ///////////////////////////////// PayloadManager::EndpointInfo::Status diff --git a/connections/implementation/payload_manager.h b/connections/implementation/payload_manager.h index 3bfce68c..acbd8656 100644 --- a/connections/implementation/payload_manager.h +++ b/connections/implementation/payload_manager.h @@ -71,6 +71,8 @@ class PayloadManager : public EndpointManager::FrameProcessor { void DisconnectFromEndpointManager(); + void SetCustomSavePath(ClientProxy* client, const std::string& path); + private: // Information about an endpoint for a particular payload. struct EndpointInfo { @@ -310,6 +312,7 @@ class PayloadManager : public EndpointManager::FrameProcessor { PayloadTransferFrame::PayloadHeader::PayloadType type); mutable Mutex mutex_; + std::string custom_save_path_; AtomicBoolean shutdown_{false}; std::unique_ptr shutdown_barrier_; int send_payload_count_ = 0; diff --git a/connections/implementation/service_controller.h b/connections/implementation/service_controller.h index d924549c..9ec920d2 100644 --- a/connections/implementation/service_controller.h +++ b/connections/implementation/service_controller.h @@ -99,6 +99,9 @@ class ServiceController { virtual void DisconnectFromEndpoint(ClientProxy* client, const std::string& endpoint_id) = 0; + + virtual void SetCustomSavePath(ClientProxy* client, + const std::string& path) = 0; }; } // namespace connections diff --git a/connections/implementation/service_controller_router.cc b/connections/implementation/service_controller_router.cc index a8c43d27..6901ac4b 100644 --- a/connections/implementation/service_controller_router.cc +++ b/connections/implementation/service_controller_router.cc @@ -343,6 +343,19 @@ void ServiceControllerRouter::StopAllEndpoints(ClientProxy* client, }); } +void ServiceControllerRouter::SetCustomSavePath( + ClientProxy* client, absl::string_view path, + const ResultCallback& callback) { + RouteToServiceController( + "scr-set-custom-save-path", [this, client, path, callback]() { + NEARBY_LOGS(INFO) << "Client " << client->GetClientId() + << " has requested us to set custom save path to " + << path; + GetServiceController()->SetCustomSavePath(client, std::string(path)); + callback.result_cb({Status::kSuccess}); + }); +} + void ServiceControllerRouter::SetServiceControllerForTesting( std::unique_ptr service_controller) { service_controller_ = std::move(service_controller); diff --git a/connections/implementation/service_controller_router.h b/connections/implementation/service_controller_router.h index be665bce..914cc102 100644 --- a/connections/implementation/service_controller_router.h +++ b/connections/implementation/service_controller_router.h @@ -108,6 +108,9 @@ class ServiceControllerRouter { virtual void StopAllEndpoints(ClientProxy* client, const ResultCallback& callback); + virtual void SetCustomSavePath(ClientProxy* client, absl::string_view path, + const ResultCallback& callback); + void SetServiceControllerForTesting( std::unique_ptr service_controller); diff --git a/internal/platform/implementation/g3/platform.cc b/internal/platform/implementation/g3/platform.cc index f242de58..8f46e46c 100644 --- a/internal/platform/implementation/g3/platform.cc +++ b/internal/platform/implementation/g3/platform.cc @@ -63,8 +63,13 @@ namespace location { namespace nearby { namespace api { +std::string ImplementationPlatform::GetCustomSavePath( + const std::string& parent_folder, const std::string& file_name) { + return file::JoinPath(parent_folder, file_name); +} + std::string ImplementationPlatform::GetDownloadPath( - absl::string_view parent_folder, absl::string_view file_name) { + const std::string& parent_folder, const std::string& file_name) { std::string fullPath("/tmp"); return file::JoinPath("/tmp", file_name); @@ -122,7 +127,7 @@ std::unique_ptr ImplementationPlatform::CreateInputFile( } std::unique_ptr ImplementationPlatform::CreateInputFile( - absl::string_view file_path, size_t size) { + const std::string& file_path, size_t size) { return shared::IOFile::CreateInputFile(file_path, size); } @@ -137,7 +142,7 @@ std::unique_ptr ImplementationPlatform::CreateOutputFile( } std::unique_ptr ImplementationPlatform::CreateOutputFile( - absl::string_view file_path) { + const std::string& file_path) { return shared::IOFile::CreateOutputFile(file_path); } diff --git a/internal/platform/implementation/ios/platform.mm b/internal/platform/implementation/ios/platform.mm index 1423302c..0c063387 100644 --- a/internal/platform/implementation/ios/platform.mm +++ b/internal/platform/implementation/ios/platform.mm @@ -36,8 +36,20 @@ namespace location { namespace nearby { namespace api { -std::string ImplementationPlatform::GetDownloadPath(absl::string_view parent_folder, - absl::string_view file_name) { +std::string ImplementationPlatform::GetCustomSavePath(const std::string& parent_folder, + const std::string& file_name) { + // TODO(b/227535777): This needs to be done correctly, we now have a file name and parent folder, + // they should be combined with the custom save path + NSString* fileName = ObjCStringFromCppString(file_name); + + // TODO(b/227535777): If file name matches an existing file, it will be overwritten. Append a + // number until a unique file name is reached 'foobar (2).png'. + + return CppStringFromObjCString([NSTemporaryDirectory() stringByAppendingPathComponent:fileName]); +} + +std::string ImplementationPlatform::GetDownloadPath(const std::string& parent_folder, + const std::string& file_name) { // TODO(jfcarroll): This needs to be done correctly, we now have a file name and parent folder, // they should be combined with the default download path NSString* fileName = ObjCStringFromCppString(file_name); @@ -84,7 +96,7 @@ std::unique_ptr ImplementationPlatform::CreateInputFile(PayloadId pay return nullptr; } -std::unique_ptr ImplementationPlatform::CreateInputFile(absl::string_view file_path, +std::unique_ptr ImplementationPlatform::CreateInputFile(const std::string& file_path, size_t size) { return shared::IOFile::CreateInputFile(file_path, size); } @@ -94,7 +106,7 @@ std::unique_ptr ImplementationPlatform::CreateOutputFile(PayloadId p return nullptr; } -std::unique_ptr ImplementationPlatform::CreateOutputFile(absl::string_view file_path) { +std::unique_ptr ImplementationPlatform::CreateOutputFile(const std::string& file_path) { return shared::IOFile::CreateOutputFile(file_path); } @@ -131,8 +143,8 @@ std::unique_ptr ImplementationPlatform::CreateBleMedium(api::Bluetoot return nullptr; } -std::unique_ptr -ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter& adapter) { +std::unique_ptr ImplementationPlatform::CreateBleV2Medium( + api::BluetoothAdapter& adapter) { return std::make_unique(adapter); } diff --git a/internal/platform/implementation/platform.h b/internal/platform/implementation/platform.h index f4b826bd..b22f76f1 100644 --- a/internal/platform/implementation/platform.h +++ b/internal/platform/implementation/platform.h @@ -66,12 +66,15 @@ class ImplementationPlatform { // - CountDownLatch : to ensure at least N threads are waiting. // - file I/O // - Logging - static std::string GetDownloadPath(absl::string_view parent_folder, - absl::string_view file_name); + static std::string GetCustomSavePath(const std::string& parent_folder, + const std::string& file_name); - static std::string GetDownloadPath(absl::string_view file_name); + static std::string GetDownloadPath(const std::string& parent_folder, + const std::string& file_name); - static std::string GetAppDataPath(absl::string_view file_name); + static std::string GetDownloadPath(const std::string& file_name); + + static std::string GetAppDataPath(const std::string& file_name); static OSName GetCurrentOS(); @@ -96,11 +99,11 @@ class ImplementationPlatform { static std::unique_ptr CreateInputFile(PayloadId, std::int64_t); - static std::unique_ptr CreateInputFile(absl::string_view, size_t); + static std::unique_ptr CreateInputFile(const std::string&, size_t); static std::unique_ptr CreateOutputFile(PayloadId); - static std::unique_ptr CreateOutputFile(absl::string_view); + static std::unique_ptr CreateOutputFile(const std::string&); static std::unique_ptr CreateLogMessage( const char* file, int line, LogMessage::Severity severity); diff --git a/internal/platform/implementation/windows/file_path.cc b/internal/platform/implementation/windows/file_path.cc index 86629664..43db2de1 100644 --- a/internal/platform/implementation/windows/file_path.cc +++ b/internal/platform/implementation/windows/file_path.cc @@ -49,6 +49,13 @@ wchar_t const* kForbiddenPathNames[] = { L"COM5", L"COM6", L"COM7", L"COM8", L"COM9", L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9"}; +std::wstring FilePath::GetCustomSavePath(std::wstring parent_folder, + std::wstring file_name) { + std::wstring path; + path += parent_folder + kPathDelimiter + file_name; + return CreateOutputFileWithRename(path); +} + std::wstring FilePath::GetDownloadPath(std::wstring parent_folder, std::wstring file_name) { return CreateOutputFileWithRename( diff --git a/internal/platform/implementation/windows/file_path.h b/internal/platform/implementation/windows/file_path.h index 418950b2..5c6c7342 100644 --- a/internal/platform/implementation/windows/file_path.h +++ b/internal/platform/implementation/windows/file_path.h @@ -1,49 +1,51 @@ -// 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. - -#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_ - -#include - -#include "absl/strings/string_view.h" - -namespace location { -namespace nearby { -namespace windows { - -class FilePath { - public: - static std::wstring GetDownloadPath(std::wstring parent_folder, - std::wstring file_name); - - private: - // If the file already exists we add " (x)", where x is an incrementing - // number, starting at 1, using the next non-existing number, to the - // file name, just before the first dot, or at the end if no dot. The - // absolute path is returned. - static std::wstring CreateOutputFileWithRename(std::wstring path); - - static void ReplaceInvalidCharacters(std::wstring& path); - static void SanitizePath(std::wstring& path); - static std::wstring MutateForbiddenPathElements(std::wstring& str); - static std::wstring GetDownloadPathInternal(std::wstring parent_folder, - std::wstring file_name); -}; - -} // namespace windows -} // namespace nearby -} // namespace location - -#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_ +// 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. + +#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_ + +#include + +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { +namespace windows { + +class FilePath { + public: + static std::wstring GetCustomSavePath(std::wstring parent_folder, + std::wstring file_name); + static std::wstring GetDownloadPath(std::wstring parent_folder, + std::wstring file_name); + + private: + // If the file already exists we add " (x)", where x is an incrementing + // number, starting at 1, using the next non-existing number, to the + // file name, just before the first dot, or at the end if no dot. The + // absolute path is returned. + static std::wstring CreateOutputFileWithRename(std::wstring path); + + static void ReplaceInvalidCharacters(std::wstring& path); + static void SanitizePath(std::wstring& path); + static std::wstring MutateForbiddenPathElements(std::wstring& str); + static std::wstring GetDownloadPathInternal(std::wstring parent_folder, + std::wstring file_name); +}; + +} // namespace windows +} // namespace nearby +} // namespace location + +#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_ diff --git a/internal/platform/implementation/windows/platform.cc b/internal/platform/implementation/windows/platform.cc index f3e007c0..7ed12cbb 100644 --- a/internal/platform/implementation/windows/platform.cc +++ b/internal/platform/implementation/windows/platform.cc @@ -93,8 +93,17 @@ std::string GetApplicationName(DWORD pid) { } // namespace +std::string ImplementationPlatform::GetCustomSavePath( + const std::string& parent_folder, const std::string& file_name) { + auto parent = windows::string_to_wstring(parent_folder); + auto file = windows::string_to_wstring(file_name); + + return windows::wstring_to_string( + windows::FilePath::GetCustomSavePath(parent, file)); +} + std::string ImplementationPlatform::GetDownloadPath( - absl::string_view parent_folder, absl::string_view file_name) { + const std::string& parent_folder, const std::string& file_name) { auto parent = windows::string_to_wstring(std::string(parent_folder)); auto file = windows::string_to_wstring(std::string(file_name)); @@ -103,7 +112,7 @@ std::string ImplementationPlatform::GetDownloadPath( } std::string ImplementationPlatform::GetDownloadPath( - absl::string_view file_name) { + const std::string& file_name) { std::wstring fake_parent_path; auto file = windows::string_to_wstring(std::string(file_name)); @@ -112,7 +121,7 @@ std::string ImplementationPlatform::GetDownloadPath( } std::string ImplementationPlatform::GetAppDataPath( - absl::string_view file_name) { + const std::string& file_name) { PWSTR basePath; // Retrieves the full path of a known folder identified by the folder's @@ -185,7 +194,7 @@ std::unique_ptr ImplementationPlatform::CreateInputFile( } std::unique_ptr ImplementationPlatform::CreateInputFile( - absl::string_view file_path, size_t size) { + const std::string& file_path, size_t size) { return windows::IOFile::CreateInputFile(file_path, size); } @@ -199,8 +208,7 @@ std::unique_ptr ImplementationPlatform::CreateOutputFile( } std::unique_ptr ImplementationPlatform::CreateOutputFile( - absl::string_view file_path) { - // TODO(jfcarroll): the following code should probably be moved to FilePath + const std::string& file_path) { std::string path(file_path); std::string folder_path = path.substr(0, path.find_last_of('/'));