1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/media_galleries/fileapi/supported_image_type_validator.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/files/scoped_platform_file_closer.h" 10 #include "base/location.h" 11 #include "base/logging.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/stl_util.h" 15 #include "base/threading/thread_restrictions.h" 16 #include "chrome/browser/image_decoder.h" 17 #include "content/public/browser/browser_thread.h" 18 19 using content::BrowserThread; 20 21 namespace chrome { 22 23 namespace { 24 25 // Arbitrary limit to sanity check the file size. 26 const int kMaxImageFileSize = 50*1014*1024; 27 28 scoped_ptr<std::string> ReadOnFileThread(const base::FilePath& path) { 29 base::ThreadRestrictions::AssertIOAllowed(); 30 scoped_ptr<std::string> result; 31 32 base::PlatformFile file = base::CreatePlatformFile( 33 path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL, NULL); 34 if (file == base::kInvalidPlatformFileValue) 35 return result.Pass(); 36 base::ScopedPlatformFileCloser file_closer(&file); 37 38 base::PlatformFileInfo file_info; 39 if (!base::GetPlatformFileInfo(file, &file_info) || 40 file_info.size > kMaxImageFileSize) { 41 return result.Pass(); 42 } 43 44 result.reset(new std::string); 45 result->resize(file_info.size); 46 if (base::ReadPlatformFile(file, 0, string_as_array(result.get()), 47 file_info.size) != file_info.size) { 48 result.reset(); 49 } 50 51 return result.Pass(); 52 } 53 54 class ImageDecoderDelegateAdapter : public ImageDecoder::Delegate { 55 public: 56 ImageDecoderDelegateAdapter( 57 scoped_ptr<std::string> data, 58 const fileapi::CopyOrMoveFileValidator::ResultCallback& callback) 59 : data_(data.Pass()), 60 callback_(callback) { 61 DCHECK(data_); 62 } 63 64 const std::string& data() { 65 return *data_; 66 } 67 68 // ImageDecoder::Delegate methods. 69 virtual void OnImageDecoded(const ImageDecoder* /*decoder*/, 70 const SkBitmap& /*decoded_image*/) OVERRIDE { 71 callback_.Run(base::PLATFORM_FILE_OK); 72 delete this; 73 } 74 75 virtual void OnDecodeImageFailed(const ImageDecoder* /*decoder*/) OVERRIDE { 76 callback_.Run(base::PLATFORM_FILE_ERROR_SECURITY); 77 delete this; 78 } 79 80 private: 81 scoped_ptr<std::string> data_; 82 fileapi::CopyOrMoveFileValidator::ResultCallback callback_; 83 84 DISALLOW_COPY_AND_ASSIGN(ImageDecoderDelegateAdapter); 85 }; 86 87 } // namespace 88 89 SupportedImageTypeValidator::~SupportedImageTypeValidator() {} 90 91 // static 92 bool SupportedImageTypeValidator::SupportsFileType(const base::FilePath& path) { 93 base::FilePath::StringType extension = path.Extension(); 94 return extension == FILE_PATH_LITERAL(".bmp") || 95 extension == FILE_PATH_LITERAL(".gif") || 96 extension == FILE_PATH_LITERAL(".jfif") || 97 extension == FILE_PATH_LITERAL(".jpeg") || 98 extension == FILE_PATH_LITERAL(".jpg") || 99 extension == FILE_PATH_LITERAL(".pjp") || 100 extension == FILE_PATH_LITERAL(".pjpeg") || 101 extension == FILE_PATH_LITERAL(".png") || 102 extension == FILE_PATH_LITERAL(".webp"); 103 } 104 105 void SupportedImageTypeValidator::StartPreWriteValidation( 106 const ResultCallback& result_callback) { 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 108 DCHECK(callback_.is_null()); 109 callback_ = result_callback; 110 111 BrowserThread::PostTaskAndReplyWithResult( 112 BrowserThread::FILE, 113 FROM_HERE, 114 base::Bind(&ReadOnFileThread, path_), 115 base::Bind(&SupportedImageTypeValidator::OnFileOpen, 116 weak_factory_.GetWeakPtr())); 117 } 118 119 SupportedImageTypeValidator::SupportedImageTypeValidator( 120 const base::FilePath& path) 121 : path_(path), 122 weak_factory_(this) { 123 } 124 125 void SupportedImageTypeValidator::OnFileOpen(scoped_ptr<std::string> data) { 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 127 if (!data.get()) { 128 callback_.Run(base::PLATFORM_FILE_ERROR_SECURITY); 129 return; 130 } 131 132 // |adapter| will delete itself after a completion message is received. 133 ImageDecoderDelegateAdapter* adapter = 134 new ImageDecoderDelegateAdapter(data.Pass(), callback_); 135 decoder_ = new ImageDecoder(adapter, adapter->data(), 136 ImageDecoder::DEFAULT_CODEC); 137 decoder_->Start(content::BrowserThread::GetMessageLoopProxyForThread( 138 BrowserThread::IO)); 139 } 140 141 } // namespace chrome 142