| // Copyright 2014 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 "extensions/browser/path_util.h" |
| |
| #include "base/bind.h" |
| #include "base/files/file_util.h" |
| #include "base/path_service.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/task_runner_util.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| #include "build/build_config.h" |
| #include "extensions/browser/extension_file_task_runner.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/text/bytes_formatting.h" |
| |
| #if defined(OS_MACOSX) |
| #include <CoreFoundation/CoreFoundation.h> |
| #include "base/mac/foundation_util.h" |
| #endif |
| |
| namespace extensions { |
| namespace path_util { |
| |
| namespace { |
| #if defined(OS_MACOSX) |
| |
| // Retrieves the localized display name for the base name of the given path. |
| // If the path is not localized, this will just return the base name. |
| std::string GetDisplayBaseName(const base::FilePath& path) { |
| base::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation( |
| NULL, (const UInt8*)path.value().c_str(), path.value().length(), true)); |
| if (!url) |
| return path.BaseName().value(); |
| |
| CFStringRef str; |
| if (LSCopyDisplayNameForURL(url, &str) != noErr) |
| return path.BaseName().value(); |
| |
| std::string result(base::SysCFStringRefToUTF8(str)); |
| CFRelease(str); |
| return result; |
| } |
| |
| #endif // defined(OS_MACOSX) |
| |
| const base::FilePath::CharType kHomeShortcut[] = FILE_PATH_LITERAL("~"); |
| |
| void OnDirectorySizeCalculated( |
| int message_id, |
| base::OnceCallback<void(const base::string16&)> callback, |
| int64_t size_in_bytes) { |
| const int one_mebibyte_in_bytes = 1024 * 1024; |
| base::string16 response = |
| size_in_bytes < one_mebibyte_in_bytes |
| ? l10n_util::GetStringUTF16(message_id) |
| : ui::FormatBytesWithUnits(size_in_bytes, ui::DATA_UNITS_MEBIBYTE, |
| true); |
| |
| std::move(callback).Run(response); |
| } |
| |
| } // namespace |
| |
| base::FilePath PrettifyPath(const base::FilePath& source_path) { |
| base::FilePath home_path; |
| if (source_path.empty() || |
| !base::PathService::Get(base::DIR_HOME, &home_path)) { |
| return source_path; |
| } |
| |
| base::FilePath display_path = base::FilePath(kHomeShortcut); |
| if (source_path == home_path) |
| return display_path; |
| |
| #if defined(OS_MACOSX) |
| DCHECK(source_path.IsAbsolute()); |
| |
| // Break down the incoming path into components, and grab the display name |
| // for every component. This will match app bundles, ".localized" folders, |
| // and localized subfolders of the user's home directory. |
| // Don't grab the display name of the first component, i.e., "/", as it'll |
| // show up as the HDD name. |
| std::vector<base::FilePath::StringType> components; |
| source_path.GetComponents(&components); |
| display_path = base::FilePath(components[0]); |
| base::FilePath actual_path = display_path; |
| for (std::vector<base::FilePath::StringType>::iterator i = |
| components.begin() + 1; i != components.end(); ++i) { |
| actual_path = actual_path.Append(*i); |
| if (actual_path == home_path) { |
| display_path = base::FilePath(kHomeShortcut); |
| home_path = base::FilePath(); |
| continue; |
| } |
| std::string display = GetDisplayBaseName(actual_path); |
| display_path = display_path.Append(display); |
| } |
| DCHECK_EQ(actual_path.value(), source_path.value()); |
| return display_path; |
| #else // defined(OS_MACOSX) |
| if (home_path.AppendRelativePath(source_path, &display_path)) |
| return display_path; |
| return source_path; |
| #endif // defined(OS_MACOSX) |
| } |
| |
| void CalculateAndFormatExtensionDirectorySize( |
| const base::FilePath& extension_path, |
| int message_id, |
| base::OnceCallback<void(const base::string16&)> callback) { |
| base::PostTaskAndReplyWithResult( |
| GetExtensionFileTaskRunner().get(), FROM_HERE, |
| base::BindOnce(&base::ComputeDirectorySize, extension_path), |
| base::BindOnce(&OnDirectorySizeCalculated, message_id, |
| std::move(callback))); |
| } |
| |
| base::FilePath ResolveHomeDirectory(const base::FilePath& path) { |
| #if defined(OS_WIN) |
| return path; |
| #else |
| const auto& value = path.value(); |
| // Look for a path starting with the "~" character. It must be alone or |
| // followed by a separator. |
| if (value.empty() || value[0] != FILE_PATH_LITERAL('~') || |
| (value.length() > 1 && !base::FilePath::IsSeparator(value[1]))) { |
| return path; |
| } |
| base::FilePath result; |
| base::PathService::Get(base::DIR_HOME, &result); |
| // The user could specify "~" or "~/", so be safe. |
| if (value.length() > 2) { |
| result = result.Append(value.substr(2)); |
| } |
| return result; |
| #endif |
| } |
| |
| } // namespace path_util |
| } // namespace extensions |