| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/shortcuts/chrome_webloc_file.h" |
| |
| #import <Foundation/Foundation.h> |
| |
| #include <utility> |
| |
| #include "base/apple/foundation_util.h" |
| #include "base/files/block_tests_writing_to_special_dirs.h" |
| #include "base/logging.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/threading/scoped_blocking_call.h" |
| |
| namespace shortcuts { |
| |
| namespace { |
| |
| NSString* const kUrlKey = @"URL"; |
| NSString* const kProfileKey = @"CrProfile"; |
| |
| } // namespace |
| |
| ChromeWeblocFile::ChromeWeblocFile(GURL target_url, |
| base::SafeBaseName profile_path_name) |
| : target_url_(std::move(target_url)), |
| profile_path_name_(std::move(profile_path_name)) {} |
| |
| ChromeWeblocFile::~ChromeWeblocFile() = default; |
| |
| // static |
| std::optional<ChromeWeblocFile> ChromeWeblocFile::LoadFromFile( |
| const base::FilePath& file_path) { |
| NSDictionary* contents; |
| NSError* error; |
| { |
| base::ScopedBlockingCall scoped_blocking_call( |
| FROM_HERE, base::BlockingType::MAY_BLOCK); |
| contents = [NSDictionary |
| dictionaryWithContentsOfURL:base::apple::FilePathToNSURL(file_path) |
| error:&error]; |
| } |
| if (!contents) { |
| LOG(ERROR) << "Failed to read shortcut file from " << file_path << ": " |
| << error; |
| return std::nullopt; |
| } |
| GURL target_url(base::SysNSStringToUTF8(contents[kUrlKey])); |
| std::optional<base::SafeBaseName> profile_path_name = |
| base::SafeBaseName::Create( |
| base::apple::NSStringToFilePath(contents[kProfileKey])); |
| if (!target_url.is_valid() || !profile_path_name.has_value() || |
| profile_path_name->path().empty()) { |
| LOG(ERROR) << "Failed to parse URL or profile from " << file_path << " " |
| << contents; |
| return std::nullopt; |
| } |
| return ChromeWeblocFile(std::move(target_url), *std::move(profile_path_name)); |
| } |
| |
| bool ChromeWeblocFile::SaveToFile(const base::FilePath& file_path) { |
| if (!base::BlockTestsWritingToSpecialDirs::CanWriteToPath(file_path)) { |
| return false; |
| } |
| |
| NSDictionary* contents = @{ |
| kUrlKey : base::SysUTF8ToNSString(target_url_.spec()), |
| kProfileKey : base::apple::FilePathToNSString(profile_path_name_.path()), |
| }; |
| { |
| base::ScopedBlockingCall scoped_blocking_call( |
| FROM_HERE, base::BlockingType::MAY_BLOCK); |
| NSError* error = nil; |
| if (![contents writeToURL:base::apple::FilePathToNSURL(file_path) |
| error:&error]) { |
| LOG(ERROR) << "Failed to create shortcut at " << file_path << ": " |
| << error; |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| } // namespace shortcuts |