forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce a helper for OPENFILENAME struct to make certain logic test…
…able. BUG=73098 R=sky@chromium.org Review URL: https://codereview.chromium.org/426673003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287048 0039d316-1c4b-4281-b951-d872f2087c98
- Loading branch information
erikwright@chromium.org
committed
Aug 1, 2014
1 parent
d9d01ea
commit 41814c9
Showing
7 changed files
with
319 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright (c) 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 "ui/base/win/open_file_name_win.h" | ||
|
||
#include "base/files/file_path.h" | ||
#include "base/strings/string_util.h" | ||
|
||
namespace ui { | ||
namespace win { | ||
|
||
OpenFileName::OpenFileName(HWND parent_window, DWORD flags) { | ||
::ZeroMemory(&openfilename_, sizeof(openfilename_)); | ||
openfilename_.lStructSize = sizeof(openfilename_); | ||
|
||
// According to http://support.microsoft.com/?scid=kb;en-us;222003&x=8&y=12, | ||
// The lpstrFile Buffer MUST be NULL Terminated. | ||
filename_buffer_[0] = 0; | ||
openfilename_.lpstrFile = filename_buffer_; | ||
openfilename_.nMaxFile = arraysize(filename_buffer_); | ||
|
||
openfilename_.Flags = flags; | ||
openfilename_.hwndOwner = parent_window; | ||
} | ||
|
||
OpenFileName::~OpenFileName() { | ||
} | ||
|
||
void OpenFileName::SetInitialSelection(const base::FilePath& initial_directory, | ||
const base::FilePath& initial_filename) { | ||
// First reset to the default case. | ||
// According to http://support.microsoft.com/?scid=kb;en-us;222003&x=8&y=12, | ||
// The lpstrFile Buffer MUST be NULL Terminated. | ||
filename_buffer_[0] = 0; | ||
openfilename_.lpstrFile = filename_buffer_; | ||
openfilename_.nMaxFile = arraysize(filename_buffer_); | ||
openfilename_.lpstrInitialDir = NULL; | ||
initial_directory_buffer_.clear(); | ||
|
||
if (initial_directory.empty()) | ||
return; | ||
|
||
initial_directory_buffer_ = initial_directory.value(); | ||
openfilename_.lpstrInitialDir = initial_directory_buffer_.c_str(); | ||
|
||
if (initial_filename.empty()) | ||
return; | ||
|
||
// The filename is ignored if no initial directory is supplied. | ||
base::wcslcpy(filename_buffer_, | ||
initial_filename.value().c_str(), | ||
arraysize(filename_buffer_)); | ||
} | ||
|
||
base::FilePath OpenFileName::GetSingleResult() { | ||
base::FilePath directory; | ||
std::vector<base::FilePath> filenames; | ||
GetResult(&directory, &filenames); | ||
if (filenames.size() != 1) | ||
return base::FilePath(); | ||
return directory.Append(filenames[0]); | ||
} | ||
|
||
void OpenFileName::GetResult(base::FilePath* directory, | ||
std::vector<base::FilePath>* filenames) { | ||
DCHECK(filenames->empty()); | ||
const wchar_t* selection = openfilename_.lpstrFile; | ||
while (*selection) { // Empty string indicates end of list. | ||
filenames->push_back(base::FilePath(selection)); | ||
// Skip over filename and null-terminator. | ||
selection += filenames->back().value().length() + 1; | ||
} | ||
if (filenames->size() == 1) { | ||
// When there is one file, it contains the path and filename. | ||
*directory = (*filenames)[0].DirName(); | ||
(*filenames)[0] = (*filenames)[0].BaseName(); | ||
} else if (filenames->size() > 1) { | ||
// Otherwise, the first string is the path, and the remainder are | ||
// filenames. | ||
*directory = (*filenames)[0]; | ||
filenames->erase(filenames->begin()); | ||
} | ||
} | ||
|
||
} // namespace win | ||
} // namespace ui |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Copyright (c) 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. | ||
|
||
#ifndef UI_BASE_WIN_OPEN_FILE_NAME_WIN_H_ | ||
#define UI_BASE_WIN_OPEN_FILE_NAME_WIN_H_ | ||
|
||
#include <Windows.h> | ||
#include <Commdlg.h> | ||
|
||
#include <vector> | ||
|
||
#include "base/macros.h" | ||
#include "base/strings/string16.h" | ||
#include "base/tuple.h" | ||
#include "ui/base/ui_base_export.h" | ||
|
||
namespace base { | ||
class FilePath; | ||
} // namespace base | ||
|
||
namespace ui { | ||
namespace win { | ||
|
||
// Encapsulates an OPENFILENAME struct and related buffers. Also provides static | ||
// methods for interpreting the properties of an OPENFILENAME. | ||
class UI_BASE_EXPORT OpenFileName { | ||
public: | ||
// Initializes the OPENFILENAME, which may be accessed using Get(). All fields | ||
// will be NULL except for |lStructSize|, |lpstrFile|, and |nMaxFile|. The | ||
// file buffer will initially contain a null-terminated empty string. | ||
OpenFileName(HWND parent_window, DWORD flags); | ||
~OpenFileName(); | ||
|
||
// Sets |lpstrInitialDir| and |lpstrFile|. | ||
void SetInitialSelection(const base::FilePath& initial_directory, | ||
const base::FilePath& initial_filename); | ||
|
||
// Returns the single selected file, or an empty path if there are more or | ||
// less than one results. | ||
base::FilePath GetSingleResult(); | ||
|
||
// Returns the selected file or files. | ||
void GetResult(base::FilePath* directory, | ||
std::vector<base::FilePath>* filenames); | ||
|
||
// Returns the OPENFILENAME structure. | ||
OPENFILENAME* GetOPENFILENAME() { return &openfilename_; } | ||
|
||
private: | ||
OPENFILENAME openfilename_; | ||
base::string16 initial_directory_buffer_; | ||
wchar_t filename_buffer_[UNICODE_STRING_MAX_CHARS]; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(OpenFileName); | ||
}; | ||
|
||
} // namespace win | ||
} // namespace ui | ||
|
||
#endif // UI_BASE_WIN_OPEN_FILE_NAME_WIN_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// Copyright (c) 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 "ui/base/win/open_file_name_win.h" | ||
|
||
#include "base/files/file_path.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
namespace { | ||
const HWND kHwnd = reinterpret_cast<HWND>(0xDEADBEEF); | ||
const DWORD kFlags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING; | ||
|
||
void SetResult(const base::string16& result, ui::win::OpenFileName* ofn) { | ||
EXPECT_GT(ofn->GetOPENFILENAME()->nMaxFile, result.size()); | ||
if (ofn->GetOPENFILENAME()->nMaxFile > result.size()) { | ||
if (!result.size()) { | ||
ofn->GetOPENFILENAME()->lpstrFile[0] = 0; | ||
} else { | ||
// Because the result has embedded nulls, we must memcpy. | ||
memcpy(ofn->GetOPENFILENAME()->lpstrFile, | ||
result.c_str(), | ||
(result.size() + 1) * sizeof(result[0])); | ||
} | ||
} | ||
} | ||
|
||
} // namespace | ||
|
||
TEST(OpenFileNameTest, Initialization) { | ||
ui::win::OpenFileName ofn(kHwnd, kFlags); | ||
EXPECT_EQ(kHwnd, ofn.GetOPENFILENAME()->hwndOwner); | ||
EXPECT_EQ(kFlags, ofn.GetOPENFILENAME()->Flags); | ||
EXPECT_EQ(sizeof(OPENFILENAME), ofn.GetOPENFILENAME()->lStructSize); | ||
ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile); | ||
ASSERT_GT(ofn.GetOPENFILENAME()->nMaxFile, 0u); | ||
EXPECT_EQ(0, ofn.GetOPENFILENAME()->lpstrFile[0]); | ||
} | ||
|
||
TEST(OpenFileNameTest, SetInitialSelection) { | ||
const base::FilePath kDirectory(L"C:\\directory\\child_directory"); | ||
const base::FilePath kFile(L"file_name.ext"); | ||
ui::win::OpenFileName ofn(kHwnd, kFlags); | ||
ofn.SetInitialSelection(kDirectory, kFile); | ||
EXPECT_EQ(kDirectory, base::FilePath(ofn.GetOPENFILENAME()->lpstrInitialDir)); | ||
EXPECT_EQ(kFile, base::FilePath(ofn.GetOPENFILENAME()->lpstrFile)); | ||
|
||
ofn.SetInitialSelection(kDirectory, base::FilePath()); | ||
EXPECT_EQ(kDirectory, base::FilePath(ofn.GetOPENFILENAME()->lpstrInitialDir)); | ||
// Filename buffer will still be a valid pointer, to receive a result. | ||
ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile); | ||
EXPECT_EQ(base::FilePath(), base::FilePath(ofn.GetOPENFILENAME()->lpstrFile)); | ||
|
||
ofn.SetInitialSelection(base::FilePath(), base::FilePath()); | ||
// No initial directory will lead to a NULL buffer. | ||
ASSERT_FALSE(ofn.GetOPENFILENAME()->lpstrInitialDir); | ||
ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile); | ||
EXPECT_EQ(base::FilePath(), base::FilePath(ofn.GetOPENFILENAME()->lpstrFile)); | ||
|
||
// Make sure that both values are cleared when directory is missing. | ||
ofn.SetInitialSelection(kDirectory, kFile); | ||
EXPECT_EQ(kDirectory, base::FilePath(ofn.GetOPENFILENAME()->lpstrInitialDir)); | ||
EXPECT_EQ(kFile, base::FilePath(ofn.GetOPENFILENAME()->lpstrFile)); | ||
ofn.SetInitialSelection(base::FilePath(), base::FilePath()); | ||
ASSERT_FALSE(ofn.GetOPENFILENAME()->lpstrInitialDir); | ||
ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile); | ||
EXPECT_EQ(base::FilePath(), base::FilePath(ofn.GetOPENFILENAME()->lpstrFile)); | ||
|
||
// File is ignored in absence of a directory. | ||
ofn.SetInitialSelection(base::FilePath(), kFile); | ||
ASSERT_FALSE(ofn.GetOPENFILENAME()->lpstrInitialDir); | ||
ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile); | ||
EXPECT_EQ(base::FilePath(), base::FilePath(ofn.GetOPENFILENAME()->lpstrFile)); | ||
} | ||
|
||
TEST(OpenFileNameTest, GetSingleResult) { | ||
const base::string16 kNull(L"\0", 1); | ||
ui::win::OpenFileName ofn(kHwnd, kFlags); | ||
base::FilePath result; | ||
|
||
SetResult(L"C:\\dir\\file" + kNull, &ofn); | ||
result = ofn.GetSingleResult(); | ||
EXPECT_EQ(base::FilePath(L"C:\\dir\\file"), result); | ||
|
||
SetResult(L"C:\\dir" + kNull + L"file" + kNull, &ofn); | ||
result = ofn.GetSingleResult(); | ||
EXPECT_EQ(base::FilePath(L"C:\\dir\\file"), result); | ||
|
||
SetResult(L"C:\\dir" + kNull + L"file" + kNull + L"otherfile" + kNull, &ofn); | ||
result = ofn.GetSingleResult(); | ||
EXPECT_EQ(base::FilePath(), result); | ||
|
||
SetResult(L"", &ofn); | ||
result = ofn.GetSingleResult(); | ||
EXPECT_EQ(base::FilePath(), result); | ||
} | ||
|
||
TEST(OpenFileNameTest, GetResult) { | ||
const base::string16 kNull(L"\0", 1); | ||
|
||
ui::win::OpenFileName ofn(kHwnd, kFlags); | ||
base::FilePath directory; | ||
std::vector<base::FilePath> filenames; | ||
|
||
SetResult(L"C:\\dir\\file" + kNull, &ofn); | ||
ofn.GetResult(&directory, &filenames); | ||
EXPECT_EQ(base::FilePath(L"C:\\dir"), directory); | ||
ASSERT_EQ(1u, filenames.size()); | ||
EXPECT_EQ(base::FilePath(L"file"), filenames[0]); | ||
|
||
directory.clear(); | ||
filenames.clear(); | ||
|
||
SetResult(L"C:\\dir" + kNull + L"file" + kNull, &ofn); | ||
ofn.GetResult(&directory, &filenames); | ||
EXPECT_EQ(base::FilePath(L"C:\\dir"), directory); | ||
ASSERT_EQ(1u, filenames.size()); | ||
EXPECT_EQ(base::FilePath(L"file"), filenames[0]); | ||
|
||
directory.clear(); | ||
filenames.clear(); | ||
|
||
SetResult(L"C:\\dir" + kNull + L"file" + kNull + L"otherfile" + kNull, &ofn); | ||
ofn.GetResult(&directory, &filenames); | ||
EXPECT_EQ(base::FilePath(L"C:\\dir"), directory); | ||
ASSERT_EQ(2u, filenames.size()); | ||
EXPECT_EQ(base::FilePath(L"file"), filenames[0]); | ||
EXPECT_EQ(base::FilePath(L"otherfile"), filenames[1]); | ||
|
||
directory.clear(); | ||
filenames.clear(); | ||
|
||
SetResult(L"", &ofn); | ||
ofn.GetResult(&directory, &filenames); | ||
EXPECT_EQ(base::FilePath(), directory); | ||
ASSERT_EQ(0u, filenames.size()); | ||
} |
Oops, something went wrong.