Commit 9825d9be authored by Jesse McKenna's avatar Jesse McKenna Committed by Commit Bot

desktop-pwas: Get install mode from user-data dir

This change adds function GetUserDataSuffix(), which returns the install
suffix (e.g. "" for the primary install mode, " SxS", " Beta", or
" Dev") given a path in the User Data folder.

It is based on GetInstallSuffix(), which does the same given a path in
the Application folder.

This new function is the first part of finding the location of
chrome.exe from within the User Data directory, where Progressive Web
App (PWA) launchers are planned to be. The next step will be a function
that uses the install mode from FindInstallMode(GetUserDataSuffix()) to
get the full path of chrome.exe, which PWAs can then use to launch.

Change-Id: If69859fc5f36b7d2d2c4262a1955bd432d983597
Bug: 960245
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1866977
Commit-Queue: Jesse McKenna <jessemckenna@google.com>
Reviewed-by: default avatarGreg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708663}
parent 01188659
...@@ -17,6 +17,8 @@ namespace install_static { ...@@ -17,6 +17,8 @@ namespace install_static {
namespace { namespace {
enum class InstallChildDir { kApplication, kUserData };
// Returns the executable path for the current process. // Returns the executable path for the current process.
std::wstring GetCurrentProcessExePath() { std::wstring GetCurrentProcessExePath() {
std::wstring exe_path(MAX_PATH, L'\0'); std::wstring exe_path(MAX_PATH, L'\0');
...@@ -27,6 +29,63 @@ std::wstring GetCurrentProcessExePath() { ...@@ -27,6 +29,63 @@ std::wstring GetCurrentProcessExePath() {
return exe_path; return exe_path;
} }
// Returns the install suffix embedded in |exe_path| or an empty string if none
// is found. |install_child_dir| is the directory directly below the one
// containing the install suffix. |exe_path| is expected be something similar to
// "...\[kProductPathName][suffix]\[install_child_dir]".
std::wstring GetInstallSuffixFromChildDir(const std::wstring& exe_path,
InstallChildDir install_child_dir) {
static constexpr wchar_t kApplicationDirName[] = L"\\Application";
static constexpr wchar_t kUserDataDirName[] = L"\\User Data";
const bool in_application_dir =
install_child_dir == InstallChildDir::kApplication;
const wchar_t* const install_child_dir_name =
in_application_dir ? kApplicationDirName : kUserDataDirName;
// Get length of |install_child_dir_name| as signed integer to allow
// comparison with the distance between iterators (which is signed).
const int install_child_dir_length =
in_application_dir ? static_cast<int>(_countof(kApplicationDirName) - 1)
: static_cast<int>(_countof(kUserDataDirName) - 1);
// Search backwards from the end of the path for |install_child_dir_name|,
// using a manual search for the sake of case-insensitivity.
if (exe_path.size() < kProductPathNameLength + install_child_dir_length)
return std::wstring();
std::wstring::const_reverse_iterator scan =
exe_path.crbegin() + (install_child_dir_length - 1);
while (_wcsnicmp(&*scan, install_child_dir_name, install_child_dir_length) &&
++scan != exe_path.crend()) {
}
if (scan == exe_path.crend())
return std::wstring();
// Ensure that the dir is followed by a separator or is at the end of the
// path.
if (scan - exe_path.crbegin() != install_child_dir_length - 1 &&
*(scan - install_child_dir_length) != L'\\') {
return std::wstring();
}
// Scan backwards to the next separator or the beginning of the path.
std::wstring::const_reverse_iterator name =
std::find(scan + 1, exe_path.crend(), L'\\');
// Back up one character to ignore the separator/end of iteration.
if (name == exe_path.crend())
name = exe_path.crbegin() + exe_path.size() - 1;
else
--name;
// Check for a match of the product directory name.
if (_wcsnicmp(&*name, kProductPathName, kProductPathNameLength))
return std::wstring();
// Return the (possibly empty) suffix betwixt the product name and
// |install_child_dir|.
return std::wstring(&*(name - kProductPathNameLength),
(name - scan) - kProductPathNameLength);
}
const InstallConstants* FindInstallMode(const std::wstring& suffix) { const InstallConstants* FindInstallMode(const std::wstring& suffix) {
// Search for a mode with the matching suffix. // Search for a mode with the matching suffix.
for (int i = 0; i < NUM_INSTALL_MODES; ++i) { for (int i = 0; i < NUM_INSTALL_MODES; ++i) {
...@@ -78,44 +137,12 @@ bool PathIsInProgramFiles(const std::wstring& path) { ...@@ -78,44 +137,12 @@ bool PathIsInProgramFiles(const std::wstring& path) {
} }
std::wstring GetInstallSuffix(const std::wstring& exe_path) { std::wstring GetInstallSuffix(const std::wstring& exe_path) {
// Search backwards from the end of the path for "\Application", using a return GetInstallSuffixFromChildDir(exe_path, InstallChildDir::kApplication);
// manual search for the sake of case-insensitivity. }
static constexpr wchar_t kInstallBinaryDir[] = L"\\Application";
constexpr size_t kInstallBinaryDirLength = _countof(kInstallBinaryDir) - 1;
if (exe_path.size() < kProductPathNameLength + kInstallBinaryDirLength)
return std::wstring();
std::wstring::const_reverse_iterator scan =
exe_path.crbegin() + (kInstallBinaryDirLength - 1);
while (_wcsnicmp(&*scan, kInstallBinaryDir, kInstallBinaryDirLength) &&
++scan != exe_path.crend()) {
}
if (scan == exe_path.crend())
return std::wstring();
// Ensure that the dir is followed by a separator or is at the end of the
// path.
if (scan - exe_path.crbegin() != kInstallBinaryDirLength - 1 &&
*(scan - kInstallBinaryDirLength) != L'\\') {
return std::wstring();
}
// Scan backwards to the next separator or the beginning of the path.
std::wstring::const_reverse_iterator name =
std::find(scan + 1, exe_path.crend(), L'\\');
// Back up one character to ignore the separator/end of iteration.
if (name == exe_path.crend())
name = exe_path.crbegin() + exe_path.size() - 1;
else
--name;
// Check for a match of the product directory name.
if (_wcsnicmp(&*name, kProductPathName, kProductPathNameLength))
return std::wstring();
// Return the (possibly empty) suffix betwixt the product name and install std::wstring GetUserDataSuffix(const std::wstring& user_data_path) {
// binary dir. return GetInstallSuffixFromChildDir(user_data_path,
return std::wstring(&*(name - kProductPathNameLength), InstallChildDir::kUserData);
(name - scan) - kProductPathNameLength);
} }
std::unique_ptr<PrimaryInstallDetails> MakeProductDetails( std::unique_ptr<PrimaryInstallDetails> MakeProductDetails(
......
...@@ -32,9 +32,14 @@ bool PathIsInProgramFiles(const std::wstring& path); ...@@ -32,9 +32,14 @@ bool PathIsInProgramFiles(const std::wstring& path);
// Returns the install suffix embedded in |exe_path| or an empty string if none // Returns the install suffix embedded in |exe_path| or an empty string if none
// is found. |exe_path| is expected be something similar to // is found. |exe_path| is expected be something similar to
// "...\[kProductName][suffix]\Application". // "...\[kProductPathName][suffix]\Application".
std::wstring GetInstallSuffix(const std::wstring& exe_path); std::wstring GetInstallSuffix(const std::wstring& exe_path);
// Returns the install suffix embedded in |user_data_path| or an empty string if
// none is found. |user_data_path| is expected be something similar to
// "...\[kProductPathName][suffix]\User Data".
std::wstring GetUserDataSuffix(const std::wstring& user_data_path);
// Creates product details for the process at |exe_path|. // Creates product details for the process at |exe_path|.
std::unique_ptr<PrimaryInstallDetails> MakeProductDetails( std::unique_ptr<PrimaryInstallDetails> MakeProductDetails(
const std::wstring& exe_path); const std::wstring& exe_path);
......
...@@ -122,6 +122,26 @@ TEST(ProductInstallDetailsTest, GetInstallSuffix) { ...@@ -122,6 +122,26 @@ TEST(ProductInstallDetailsTest, GetInstallSuffix) {
} }
} }
TEST(ProductInstallDetailsTest, GetUserDataSuffix) {
std::wstring suffix;
const std::pair<const wchar_t*, const wchar_t*> kData[] = {
{L"%ls\\User Data", L""},
{L"%ls\\User Data\\", L""},
{L"\\%ls\\User Data", L""},
{L"\\%ls\\User Data\\", L""},
{L"C:\\foo\\%ls\\User Data\\foo.exe", L""},
{L"%ls Blorf\\User Data", L" Blorf"},
{L"%ls Blorf\\User Data\\", L" Blorf"},
{L"\\%ls Blorf\\User Data", L" Blorf"},
{L"\\%ls Blorf\\User Data\\", L" Blorf"},
{L"C:\\foo\\%ls Blorf\\User Data\\foo.exe", L" Blorf"},
};
for (const auto& data : kData) {
const std::wstring path = base::StringPrintf(data.first, kProductPathName);
EXPECT_EQ(std::wstring(data.second), GetUserDataSuffix(path)) << path;
}
}
struct TestData { struct TestData {
const wchar_t* path; const wchar_t* path;
InstallConstantIndex index; InstallConstantIndex index;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment