From 22de64a3653834acad2580ded12857385e3d4d65 Mon Sep 17 00:00:00 2001 From: erikchen Date: Fri, 10 Oct 2014 11:27:43 -0700 Subject: [PATCH] mac: Zip packages when they are selected by the file opener. When a package is selected in the file opener, it is automatically zipped, and the zipped file is passed to the render view host. This CL fixes 2 unrelated bugs in file_select_helper: - If the render_view_host_ was destroyed before the user finished with the file_select_helper, then Release() would never be called and the file_select_helper would leak. - If the render_view_host_ was destroyed before the user finished with the file_select_helper, the default directory would be updated if the user was opening multiple files, but it would not be updated if the user was opening a single file. Now both update the default directory. Note: When a large package is being zipped, the UI thread and renderer are still responsive, but display no indication of the ongoing work. BUG=33920 Review URL: https://codereview.chromium.org/634833003 Cr-Commit-Position: refs/heads/master@{#299143} --- chrome/browser/file_select_helper.cc | 91 +++- chrome/browser/file_select_helper.h | 32 ++ chrome/browser/file_select_helper_mac.mm | 142 ++++++ chrome/browser/file_select_helper_unittest.cc | 63 ++- chrome/chrome_browser.gypi | 1 + .../CalculatorFake.app/Contents/Info.plist | 62 +++ .../Contents/MacOS/Calculator | Bin 0 -> 14996 bytes .../CalculatorFake.app/Contents/PkgInfo | 1 + .../Contents/_CodeSignature/CodeResources | 468 ++++++++++++++++++ .../CalculatorFake.app/Contents/version.plist | 16 + ui/shell_dialogs/select_file_dialog_mac.mm | 16 +- 11 files changed, 851 insertions(+), 41 deletions(-) create mode 100644 chrome/browser/file_select_helper_mac.mm create mode 100644 chrome/test/data/file_select_helper/CalculatorFake.app/Contents/Info.plist create mode 100644 chrome/test/data/file_select_helper/CalculatorFake.app/Contents/MacOS/Calculator create mode 100644 chrome/test/data/file_select_helper/CalculatorFake.app/Contents/PkgInfo create mode 100644 chrome/test/data/file_select_helper/CalculatorFake.app/Contents/_CodeSignature/CodeResources create mode 100644 chrome/test/data/file_select_helper/CalculatorFake.app/Contents/version.plist diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc index c11ea3f40d2382..4675d6481e20dc 100644 --- a/chrome/browser/file_select_helper.cc +++ b/chrome/browser/file_select_helper.cc @@ -70,6 +70,11 @@ std::vector FilePathListToSelectedFileInfoList( return selected_files; } +void DeleteFiles(const std::vector& paths) { + for (auto& file_path : paths) + base::DeleteFile(file_path, false); +} + } // namespace struct FileSelectHelper::ActiveDirectoryEnumeration { @@ -126,11 +131,13 @@ void FileSelectHelper::FileSelectedWithExtraInfo( const ui::SelectedFileInfo& file, int index, void* params) { - if (!render_view_host_) - return; - profile_->set_last_selected_directory(file.file_path.DirName()); + if (!render_view_host_) { + RunFileChooserEnd(); + return; + } + const base::FilePath& path = file.local_path; if (dialog_type_ == ui::SelectFileDialog::SELECT_UPLOAD_FOLDER) { StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_); @@ -139,10 +146,15 @@ void FileSelectHelper::FileSelectedWithExtraInfo( std::vector files; files.push_back(file); - NotifyRenderViewHost(render_view_host_, files, dialog_mode_); - // No members should be accessed from here on. - RunFileChooserEnd(); +#if defined(OS_MACOSX) && !defined(OS_IOS) + content::BrowserThread::PostTask( + content::BrowserThread::FILE_USER_BLOCKING, + FROM_HERE, + base::Bind(&FileSelectHelper::ProcessSelectedFilesMac, this, files)); +#else + NotifyRenderViewHostAndEnd(files); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) } void FileSelectHelper::MultiFilesSelected( @@ -159,27 +171,19 @@ void FileSelectHelper::MultiFilesSelectedWithExtraInfo( void* params) { if (!files.empty()) profile_->set_last_selected_directory(files[0].file_path.DirName()); - if (!render_view_host_) - return; - NotifyRenderViewHost(render_view_host_, files, dialog_mode_); - - // No members should be accessed from here on. - RunFileChooserEnd(); +#if defined(OS_MACOSX) && !defined(OS_IOS) + content::BrowserThread::PostTask( + content::BrowserThread::FILE_USER_BLOCKING, + FROM_HERE, + base::Bind(&FileSelectHelper::ProcessSelectedFilesMac, this, files)); +#else + NotifyRenderViewHostAndEnd(files); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) } void FileSelectHelper::FileSelectionCanceled(void* params) { - if (!render_view_host_) - return; - - // If the user cancels choosing a file to upload we pass back an - // empty vector. - NotifyRenderViewHost( - render_view_host_, std::vector(), - dialog_mode_); - - // No members should be accessed from here on. - RunFileChooserEnd(); + NotifyRenderViewHostAndEnd(std::vector()); } void FileSelectHelper::StartNewEnumeration(const base::FilePath& path, @@ -237,6 +241,22 @@ void FileSelectHelper::OnListDone(int id, int error) { EnumerateDirectoryEnd(); } +void FileSelectHelper::NotifyRenderViewHostAndEnd( + const std::vector& files) { + if (render_view_host_) + NotifyRenderViewHost(render_view_host_, files, dialog_mode_); + + // No members should be accessed from here on. + RunFileChooserEnd(); +} + +void FileSelectHelper::DeleteTemporaryFiles() { + BrowserThread::PostTask(BrowserThread::FILE, + FROM_HERE, + base::Bind(&DeleteFiles, temporary_files_)); + temporary_files_.clear(); +} + scoped_ptr FileSelectHelper::GetFileTypesFromAcceptType( const std::vector& accept_types) { @@ -335,8 +355,12 @@ void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host, render_view_host_ = render_view_host; web_contents_ = web_contents; notification_registrar_.RemoveAll(); + notification_registrar_.Add(this, + content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, + content::Source(web_contents_)); notification_registrar_.Add( - this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, + this, + content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, content::Source(render_view_host_)); notification_registrar_.Add( this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, @@ -433,6 +457,12 @@ void FileSelectHelper::RunFileChooserOnUIThread( // chooser dialog. Perform any cleanup and release the reference we added // in RunFileChooser(). void FileSelectHelper::RunFileChooserEnd() { + // If there are temporary files, then this instance needs to stick around + // until web_contents_ is destroyed, so that this instance can delete the + // temporary files. + if (!temporary_files_.empty()) + return; + render_view_host_ = NULL; web_contents_ = NULL; Release(); @@ -472,9 +502,20 @@ void FileSelectHelper::Observe(int type, case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { DCHECK(content::Source(source).ptr() == web_contents_); web_contents_ = NULL; - break; } + // Intentional fall through. + case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: + if (!temporary_files_.empty()) { + DeleteTemporaryFiles(); + + // Now that the temporary files have been scheduled for deletion, there + // is no longer any reason to keep this instance around. + Release(); + } + + break; + default: NOTREACHED(); } diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h index 5568478da5ffd6..cc0db8a31ca04d 100644 --- a/chrome/browser/file_select_helper.h +++ b/chrome/browser/file_select_helper.h @@ -48,6 +48,7 @@ class FileSelectHelper private: friend class base::RefCountedThreadSafe; FRIEND_TEST_ALL_PREFIXES(FileSelectHelperTest, IsAcceptTypeValid); + FRIEND_TEST_ALL_PREFIXES(FileSelectHelperTest, ZipPackage); explicit FileSelectHelper(Profile* profile); virtual ~FileSelectHelper(); @@ -121,6 +122,33 @@ class FileSelectHelper // callback is received from the enumeration code. void EnumerateDirectoryEnd(); +#if defined(OS_MACOSX) && !defined(OS_IOS) + // Must be called on the FILE_USER_BLOCKING thread. Each selected file that is + // a package will be zipped, and the zip will be passed to the render view + // host in place of the package. + void ProcessSelectedFilesMac(const std::vector& files); + + // Saves the paths of |zipped_files| for later deletion. Passes |files| to the + // render view host. + void ProcessSelectedFilesMacOnUIThread( + const std::vector& files, + const std::vector& zipped_files); + + // Zips the package at |path| into a temporary destination. Returns the + // temporary destination, if the zip was successful. Otherwise returns an + // empty path. + static base::FilePath ZipPackage(const base::FilePath& path); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + + // Utility method that passes |files| to the render view host, and ends the + // file chooser. + void NotifyRenderViewHostAndEnd( + const std::vector& files); + + // Schedules the deletion of the files in |temporary_files_| and clears the + // vector. + void DeleteTemporaryFiles(); + // Helper method to get allowed extensions for select file dialog from // the specified accept types as defined in the spec: // http://whatwg.org/html/number-state.html#attr-input-accept @@ -161,6 +189,10 @@ class FileSelectHelper // Registrar for notifications regarding our RenderViewHost. content::NotificationRegistrar notification_registrar_; + // Temporary files only used on OSX. This class is responsible for deleting + // these files when they are no longer needed. + std::vector temporary_files_; + DISALLOW_COPY_AND_ASSIGN(FileSelectHelper); }; diff --git a/chrome/browser/file_select_helper_mac.mm b/chrome/browser/file_select_helper_mac.mm new file mode 100644 index 00000000000000..4f0f4aad8cde97 --- /dev/null +++ b/chrome/browser/file_select_helper_mac.mm @@ -0,0 +1,142 @@ +// 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 "chrome/browser/file_select_helper.h" + +#include +#include + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/mac/foundation_util.h" +#include "content/public/browser/browser_thread.h" +#include "third_party/zlib/google/zip.h" +#include "ui/shell_dialogs/selected_file_info.h" + +namespace { + +// Given the |path| of a package, returns the destination that the package +// should be zipped to. Returns an empty path on any errors. +base::FilePath ZipDestination(const base::FilePath& path) { + NSMutableString* dest = + [NSMutableString stringWithString:NSTemporaryDirectory()]; + + // Couldn't get the temporary directory. + if (!dest) + return base::FilePath(); + + [dest appendFormat:@"%@/zip_cache/%@", + [[NSBundle mainBundle] bundleIdentifier], + [[NSProcessInfo processInfo] globallyUniqueString]]; + + return base::mac::NSStringToFilePath(dest); +} + +// Returns the path of the package and its components relative to the package's +// parent directory. +std::vector RelativePathsForPackage( + const base::FilePath& package) { + // Get the base directory. + base::FilePath base_dir = package.DirName(); + + // Add the package as the first relative path. + std::vector relative_paths; + relative_paths.push_back(package.BaseName()); + + // Add the components of the package as relative paths. + base::FileEnumerator file_enumerator( + package, + true /* recursive */, + base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); + for (base::FilePath path = file_enumerator.Next(); !path.empty(); + path = file_enumerator.Next()) { + base::FilePath relative_path; + bool success = base_dir.AppendRelativePath(path, &relative_path); + if (success) + relative_paths.push_back(relative_path); + } + + return relative_paths; +} + +} // namespace + +base::FilePath FileSelectHelper::ZipPackage(const base::FilePath& path) { + base::FilePath dest(ZipDestination(path)); + if (dest.empty()) + return dest; + + if (!base::CreateDirectory(dest.DirName())) + return base::FilePath(); + + base::File file(dest, base::File::FLAG_CREATE | base::File::FLAG_WRITE); + if (!file.IsValid()) + return base::FilePath(); + + std::vector files_to_zip(RelativePathsForPackage(path)); + base::FilePath base_dir = path.DirName(); + bool success = zip::ZipFiles(base_dir, files_to_zip, file.GetPlatformFile()); + + int result = -1; + if (success) + result = fchmod(file.GetPlatformFile(), S_IRUSR); + + return result >= 0 ? dest : base::FilePath(); +} + +void FileSelectHelper::ProcessSelectedFilesMac( + const std::vector& files) { + DCHECK_CURRENTLY_ON(content::BrowserThread::FILE_USER_BLOCKING); + + // Make a mutable copy of the input files. + std::vector files_out(files); + std::vector temporary_files; + + for (auto& file_info : files_out) { + NSString* filename = base::mac::FilePathToNSString(file_info.local_path); + BOOL isPackage = + [[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename]; + if (isPackage && base::DirectoryExists(file_info.local_path)) { + base::FilePath result = ZipPackage(file_info.local_path); + + if (!result.empty()) { + temporary_files.push_back(result); + file_info.local_path = result; + file_info.file_path = result; + file_info.display_name.append(".zip"); + } + } + } + + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&FileSelectHelper::ProcessSelectedFilesMacOnUIThread, + base::Unretained(this), + files_out, + temporary_files)); +} + +void FileSelectHelper::ProcessSelectedFilesMacOnUIThread( + const std::vector& files, + const std::vector& temporary_files) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (!temporary_files.empty()) { + temporary_files_.insert( + temporary_files_.end(), temporary_files.begin(), temporary_files.end()); + + // Typically, |temporary_files| are deleted after |web_contents_| is + // destroyed. If |web_contents_| is already NULL, then the temporary files + // need to be deleted now. + if (!web_contents_) { + DeleteTemporaryFiles(); + RunFileChooserEnd(); + return; + } + } + + NotifyRenderViewHostAndEnd(files); +} diff --git a/chrome/browser/file_select_helper_unittest.cc b/chrome/browser/file_select_helper_unittest.cc index 5eb0436957f754..9c5fbe917805de 100644 --- a/chrome/browser/file_select_helper_unittest.cc +++ b/chrome/browser/file_select_helper_unittest.cc @@ -2,10 +2,36 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/macros.h" +#include "base/path_service.h" +#include "base/process/launch.h" #include "chrome/browser/file_select_helper.h" +#include "chrome/common/chrome_paths.h" #include "testing/gtest/include/gtest/gtest.h" -TEST(FileSelectHelperTest, IsAcceptTypeValid) { +class FileSelectHelperTest : public testing::Test { + public: + FileSelectHelperTest() {} + + protected: + virtual void SetUp() override { + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_dir_)); + data_dir_ = data_dir_.AppendASCII("file_select_helper"); + ASSERT_TRUE(base::PathExists(data_dir_)); + } + + // The path to input data used in tests. + base::FilePath data_dir_; + + private: + DISALLOW_COPY_AND_ASSIGN(FileSelectHelperTest); +}; + +TEST_F(FileSelectHelperTest, IsAcceptTypeValid) { EXPECT_TRUE(FileSelectHelper::IsAcceptTypeValid("a/b")); EXPECT_TRUE(FileSelectHelper::IsAcceptTypeValid("abc/def")); EXPECT_TRUE(FileSelectHelper::IsAcceptTypeValid("abc/*")); @@ -17,3 +43,38 @@ TEST(FileSelectHelperTest, IsAcceptTypeValid) { EXPECT_FALSE(FileSelectHelper::IsAcceptTypeValid("ABC/*")); EXPECT_FALSE(FileSelectHelper::IsAcceptTypeValid("abc/def ")); } + +#if defined(OS_MACOSX) && !defined(OS_IOS) +TEST_F(FileSelectHelperTest, ZipPackage) { + // Zip the package. + const char app_name[] = "CalculatorFake.app"; + base::FilePath src = data_dir_.Append(app_name); + base::FilePath dest = FileSelectHelper::ZipPackage(src); + ASSERT_FALSE(dest.empty()); + ASSERT_TRUE(base::PathExists(dest)); + + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + // Unzip the package into a temporary directory. + CommandLine cl(base::FilePath("/usr/bin/unzip")); + cl.AppendArg(dest.value().c_str()); + cl.AppendArg("-d"); + cl.AppendArg(temp_dir.path().value().c_str()); + std::string output; + EXPECT_TRUE(base::GetAppOutput(cl, &output)); + + // Verify that several key files haven't changed. + const char* files_to_verify[] = {"Contents/Info.plist", + "Contents/MacOS/Calculator", + "Contents/_CodeSignature/CodeResources"}; + size_t file_count = arraysize(files_to_verify); + for (size_t i = 0; i < file_count; i++) { + const char* relative_path = files_to_verify[i]; + base::FilePath orig_file = src.Append(relative_path); + base::FilePath final_file = + temp_dir.path().Append(app_name).Append(relative_path); + EXPECT_TRUE(base::ContentsEqual(orig_file, final_file)); + } +} +#endif // defined(OS_MACOSX) && !defined(OS_IOS) diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index cbcd0fe2fdccfa..c6070c60e2865a 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -412,6 +412,7 @@ 'browser/favicon/favicon_tab_helper.h', 'browser/file_select_helper.cc', 'browser/file_select_helper.h', + 'browser/file_select_helper_mac.mm', 'browser/flags_storage.h', 'browser/fullscreen.h', 'browser/fullscreen_chromeos.cc', diff --git a/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/Info.plist b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/Info.plist new file mode 100644 index 00000000000000..39c38a4dec62f0 --- /dev/null +++ b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/Info.plist @@ -0,0 +1,62 @@ + + + + + BuildMachineOSBuild + 13A3007 + CFBundleDevelopmentRegion + English + CFBundleExecutable + Calculator + CFBundleGetInfoString + 10.8, Copyright © 2001-2013, Apple Inc. + CFBundleHelpBookFolder + Calculator.help + CFBundleHelpBookName + com.apple.Calculator.help + CFBundleIconFile + Calculator.icns + CFBundleIdentifier + com.apple.calculator + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Calculator + CFBundlePackageType + APPL + CFBundleShortVersionString + 10.8 + CFBundleSignature + ???? + CFBundleVersion + 123 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 5A11344p + DTPlatformVersion + GM + DTSDKBuild + 13A3007 + DTSDKName + + DTXcode + 0500 + DTXcodeBuild + 5A11344p + LSApplicationCategoryType + public.app-category.utilities + LSApplicationSecondaryCategoryType + public.app-category.productivity + LSHasLocalizedDisplayName + + LSMinimumSystemVersion + 10.8.0 + NSMainNibFile + Calculator + NSPrincipalClass + NSApplication + NSSupportsSuddenTermination + + + diff --git a/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/MacOS/Calculator b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/MacOS/Calculator new file mode 100644 index 0000000000000000000000000000000000000000..524c66af689ff222a71e5c08f47f1260ec13a5bd GIT binary patch literal 14996 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 literal 0 HcmV?d00001 diff --git a/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/PkgInfo b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/PkgInfo new file mode 100644 index 00000000000000..bd04210fb49f60 --- /dev/null +++ b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/_CodeSignature/CodeResources b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/_CodeSignature/CodeResources new file mode 100644 index 00000000000000..9ba6ef09cfc68b --- /dev/null +++ b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/_CodeSignature/CodeResources @@ -0,0 +1,468 @@ + + + + + files + + Resources/Calculator.icns + + Gn02zgleVXVUNMx/IaKHRdogAqc= + + Resources/ConversionCategories.plist + + T8VrSycV7UZI+iraTkfRzXgGpCg= + + Resources/ConversionsFromBase.plist + + C+GN4i6J6fHEGyrL76HwoWD0jwY= + + Resources/ConversionsToBase.plist + + BIGpxM7D5Nd65DZUxGj8RTKhMa4= + + Resources/English.lproj/Calculator.nib + + hash + + BoYRTYGybnwwBjfhJXPnMV/SDEI= + + optional + + + Resources/English.lproj/ConversionSheet.nib + + hash + + F8hm0ey2/eT6E+COCmhyuMBgVGU= + + optional + + + Resources/English.lproj/InfoPlist.strings + + hash + + 5Pi5eQt8nOjHiAznV6EBZs18uzk= + + optional + + + Resources/English.lproj/Localizable.strings + + hash + + R/eA28xGdzOwu+MiJas13zJLGKA= + + optional + + + Resources/English.lproj/UnitNames.strings + + hash + + CG6oiCqvbVg7cSQxhNIqPMIeygg= + + optional + + + Resources/English.lproj/locversion.plist + + hash + + 58hId6E9Y7r4mNPv7xXxf0VWs18= + + optional + + + Resources/FinancialRates.xml + + qWkmKOHKPg/lbHrldBSFqjOaB+A= + + Resources/Functions.xml + + CW8oJW4TDD/rsTbs2Nvusey0MWk= + + Resources/Speakable.plist + + ugbtHEF/8x4Bumr8ru2Vjj9BUDE= + + Resources/Yahoologo.tiff + + 2ZEUVAM/PWFrDo96CnG25ZoLDSg= + + Resources/lcd-bottomleft.tiff + + wgVRVAoNvHqdx7yXgkBTbh8a+OI= + + Resources/lcd-bottommid.tiff + + 24Ce6wJF4s/8xy7LrZS7EnFIrtQ= + + Resources/lcd-bottomright.tiff + + 3jbeGXx/YB9ZVYE74WDf19hhvGo= + + Resources/lcd-leftmid.tiff + + cfAXp+8CHYpky2NJ5bAy8dgXW/Q= + + Resources/lcd-mid.tiff + + sh4nz6P/COdaA3VRC/mUhUMd2ZA= + + Resources/lcd-rightmid.tiff + + qDP+/eBzHF+AZ4FcDa9uusnotzE= + + Resources/lcd-topleft.tiff + + VO2m5Y1RJbmZyvF7O5Ka8pXa3IE= + + Resources/lcd-topmid.tiff + + OXoawx1x1At1w4Mg+PRwY4sY1Mw= + + Resources/lcd-topright.tiff + + IroGNppXkS+YkGnTBOX5bap2Nvs= + + version.plist + + pW4t92cdIGxgxkmnrFMXAEhELDM= + + + files2 + + Info.plist + + 6KZkeVzwpeLSjgkv20DOgFpcSFA= + + PkgInfo + + n57qDP4tZfLD1rCS43W0B4LQjzE= + + Resources/Calculator.icns + + Gn02zgleVXVUNMx/IaKHRdogAqc= + + Resources/ConversionCategories.plist + + T8VrSycV7UZI+iraTkfRzXgGpCg= + + Resources/ConversionsFromBase.plist + + C+GN4i6J6fHEGyrL76HwoWD0jwY= + + Resources/ConversionsToBase.plist + + BIGpxM7D5Nd65DZUxGj8RTKhMa4= + + Resources/English.lproj/Calculator.nib + + hash + + BoYRTYGybnwwBjfhJXPnMV/SDEI= + + optional + + + Resources/English.lproj/ConversionSheet.nib + + hash + + F8hm0ey2/eT6E+COCmhyuMBgVGU= + + optional + + + Resources/English.lproj/InfoPlist.strings + + hash + + 5Pi5eQt8nOjHiAznV6EBZs18uzk= + + optional + + + Resources/English.lproj/Localizable.strings + + hash + + R/eA28xGdzOwu+MiJas13zJLGKA= + + optional + + + Resources/English.lproj/UnitNames.strings + + hash + + CG6oiCqvbVg7cSQxhNIqPMIeygg= + + optional + + + Resources/English.lproj/locversion.plist + + hash + + 58hId6E9Y7r4mNPv7xXxf0VWs18= + + optional + + + Resources/FinancialRates.xml + + qWkmKOHKPg/lbHrldBSFqjOaB+A= + + Resources/Functions.xml + + CW8oJW4TDD/rsTbs2Nvusey0MWk= + + Resources/Speakable.plist + + ugbtHEF/8x4Bumr8ru2Vjj9BUDE= + + Resources/Yahoologo.tiff + + 2ZEUVAM/PWFrDo96CnG25ZoLDSg= + + Resources/lcd-bottomleft.tiff + + wgVRVAoNvHqdx7yXgkBTbh8a+OI= + + Resources/lcd-bottommid.tiff + + 24Ce6wJF4s/8xy7LrZS7EnFIrtQ= + + Resources/lcd-bottomright.tiff + + 3jbeGXx/YB9ZVYE74WDf19hhvGo= + + Resources/lcd-leftmid.tiff + + cfAXp+8CHYpky2NJ5bAy8dgXW/Q= + + Resources/lcd-mid.tiff + + sh4nz6P/COdaA3VRC/mUhUMd2ZA= + + Resources/lcd-rightmid.tiff + + qDP+/eBzHF+AZ4FcDa9uusnotzE= + + Resources/lcd-topleft.tiff + + VO2m5Y1RJbmZyvF7O5Ka8pXa3IE= + + Resources/lcd-topmid.tiff + + OXoawx1x1At1w4Mg+PRwY4sY1Mw= + + Resources/lcd-topright.tiff + + IroGNppXkS+YkGnTBOX5bap2Nvs= + + version.plist + + pW4t92cdIGxgxkmnrFMXAEhELDM= + + + rules + + @[0-9]+ + + omit + + weight + 10 + + \.licns$ + + optional + + weight + 50 + + ^Resources/ + + ^Resources/.*\.lproj/ + + omit + + weight + 30 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 30 + + ^Resources/.*\.nib/classes\.nib$ + + optional + + weight + 5 + + ^Resources/.*\.nib/data\.dependency$ + + optional + + weight + 5 + + ^Resources/.*\.nib/designable\.nib$ + + optional + + weight + 5 + + ^Resources/.*\.nib/info\.nib$ + + optional + + weight + 5 + + ^Resources/Base\.lproj/ + + optional + + weight + 35 + + ^Resources/BridgeSupport/[^/]*\.(bridgesupport|dylib)$ + + omit + + weight + 10 + + ^Resources/Calculator.help/ + + omit + + weight + 50 + + ^Resources/English\.lproj/ + + optional + + weight + 40 + + ^version.plist$ + + + rules2 + + @[0-9]+ + + omit + + weight + 10 + + \.licns$ + + optional + + weight + 50 + + ^(Frameworks|SharedFrameworks|Plugins|Plug-ins|XPCServices|Helpers|MacOS)/ + + nested + + weight + 0.0 + + ^Resources/ + + ^Resources/.*\.lproj/ + + omit + + weight + 30 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 30 + + ^Resources/.*\.nib/classes\.nib$ + + optional + + weight + 5 + + ^Resources/.*\.nib/data\.dependency$ + + optional + + weight + 5 + + ^Resources/.*\.nib/designable\.nib$ + + optional + + weight + 5 + + ^Resources/.*\.nib/info\.nib$ + + optional + + weight + 5 + + ^Resources/Base\.lproj/ + + optional + + weight + 35 + + ^Resources/BridgeSupport/[^/]*\.(bridgesupport|dylib)$ + + omit + + weight + 10 + + ^Resources/Calculator.help/ + + omit + + weight + 50 + + ^Resources/English\.lproj/ + + optional + + weight + 40 + + ^[^/]+$ + + top + + weight + 0.0 + + ^version.plist$ + + + + diff --git a/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/version.plist b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/version.plist new file mode 100644 index 00000000000000..eef43aa38e2355 --- /dev/null +++ b/chrome/test/data/file_select_helper/CalculatorFake.app/Contents/version.plist @@ -0,0 +1,16 @@ + + + + + BuildVersion + 80 + CFBundleShortVersionString + 10.8 + CFBundleVersion + 123 + ProjectName + Calculator + SourceVersion + 128000000000000 + + diff --git a/ui/shell_dialogs/select_file_dialog_mac.mm b/ui/shell_dialogs/select_file_dialog_mac.mm index da32582684e065..a0d75e52d3fad6 100644 --- a/ui/shell_dialogs/select_file_dialog_mac.mm +++ b/ui/shell_dialogs/select_file_dialog_mac.mm @@ -75,8 +75,6 @@ void FileWasSelected(NSSavePanel* dialog, const std::vector& files, int index); - bool ShouldEnableFilename(NSSavePanel* dialog, NSString* filename); - protected: // SelectFileDialog implementation. // |params| is user data we pass back via the Listener interface. @@ -159,16 +157,6 @@ virtual void SelectFileImpl( } } -bool SelectFileDialogImpl::ShouldEnableFilename(NSSavePanel* dialog, - NSString* filename) { - // If this is a single/multiple open file dialog, disable selecting packages. - if (type_map_[dialog] != SELECT_OPEN_FILE && - type_map_[dialog] != SELECT_OPEN_MULTI_FILE) - return true; - - return ![[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename]; -} - void SelectFileDialogImpl::SelectFileImpl( Type type, const base::string16& title, @@ -427,9 +415,7 @@ - (void)endedPanel:(NSSavePanel*)panel } - (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url { - if (![url isFileURL]) - return NO; - return selectFileDialogImpl_->ShouldEnableFilename(sender, [url path]); + return [url isFileURL]; } @end