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/file.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 { 22 23 // Arbitrary limit to sanity check the file size. 24 const int kMaxImageFileSize = 50*1014*1024; 25 26 scoped_ptr<std::string> ReadOnFileThread(const base::FilePath& path) { 27 base::ThreadRestrictions::AssertIOAllowed(); 28 scoped_ptr<std::string> result; 29 30 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); 31 if (!file.IsValid()) 32 return result.Pass(); 33 34 base::File::Info file_info; 35 if (!file.GetInfo(&file_info) || 36 file_info.size > kMaxImageFileSize) { 37 return result.Pass(); 38 } 39 40 result.reset(new std::string); 41 result->resize(file_info.size); 42 if (file.Read(0, string_as_array(result.get()), file_info.size) != 43 file_info.size) { 44 result.reset(); 45 } 46 47 return result.Pass(); 48 } 49 50 class ImageDecoderDelegateAdapter : public ImageDecoder::Delegate { 51 public: 52 ImageDecoderDelegateAdapter( 53 scoped_ptr<std::string> data, 54 const fileapi::CopyOrMoveFileValidator::ResultCallback& callback) 55 : data_(data.Pass()), 56 callback_(callback) { 57 DCHECK(data_); 58 } 59 60 const std::string& data() { 61 return *data_; 62 } 63 64 // ImageDecoder::Delegate methods. 65 virtual void OnImageDecoded(const ImageDecoder* /*decoder*/, 66 const SkBitmap& /*decoded_image*/) OVERRIDE { 67 callback_.Run(base::File::FILE_OK); 68 delete this; 69 } 70 71 virtual void OnDecodeImageFailed(const ImageDecoder* /*decoder*/) OVERRIDE { 72 callback_.Run(base::File::FILE_ERROR_SECURITY); 73 delete this; 74 } 75 76 private: 77 scoped_ptr<std::string> data_; 78 fileapi::CopyOrMoveFileValidator::ResultCallback callback_; 79 80 DISALLOW_COPY_AND_ASSIGN(ImageDecoderDelegateAdapter); 81 }; 82 83 } // namespace 84 85 SupportedImageTypeValidator::~SupportedImageTypeValidator() {} 86 87 // static 88 bool SupportedImageTypeValidator::SupportsFileType(const base::FilePath& path) { 89 base::FilePath::StringType extension = path.Extension(); 90 return extension == FILE_PATH_LITERAL(".bmp") || 91 extension == FILE_PATH_LITERAL(".gif") || 92 extension == FILE_PATH_LITERAL(".jfif") || 93 extension == FILE_PATH_LITERAL(".jpeg") || 94 extension == FILE_PATH_LITERAL(".jpg") || 95 extension == FILE_PATH_LITERAL(".pjp") || 96 extension == FILE_PATH_LITERAL(".pjpeg") || 97 extension == FILE_PATH_LITERAL(".png") || 98 extension == FILE_PATH_LITERAL(".webp"); 99 } 100 101 void SupportedImageTypeValidator::StartPreWriteValidation( 102 const ResultCallback& result_callback) { 103 DCHECK_CURRENTLY_ON(BrowserThread::IO); 104 DCHECK(callback_.is_null()); 105 callback_ = result_callback; 106 107 BrowserThread::PostTaskAndReplyWithResult( 108 BrowserThread::FILE, 109 FROM_HERE, 110 base::Bind(&ReadOnFileThread, path_), 111 base::Bind(&SupportedImageTypeValidator::OnFileOpen, 112 weak_factory_.GetWeakPtr())); 113 } 114 115 SupportedImageTypeValidator::SupportedImageTypeValidator( 116 const base::FilePath& path) 117 : path_(path), 118 weak_factory_(this) { 119 } 120 121 void SupportedImageTypeValidator::OnFileOpen(scoped_ptr<std::string> data) { 122 DCHECK_CURRENTLY_ON(BrowserThread::IO); 123 if (!data.get()) { 124 callback_.Run(base::File::FILE_ERROR_SECURITY); 125 return; 126 } 127 128 // |adapter| will delete itself after a completion message is received. 129 ImageDecoderDelegateAdapter* adapter = 130 new ImageDecoderDelegateAdapter(data.Pass(), callback_); 131 decoder_ = new ImageDecoder(adapter, adapter->data(), 132 ImageDecoder::DEFAULT_CODEC); 133 decoder_->Start(content::BrowserThread::GetMessageLoopProxyForThread( 134 BrowserThread::IO)); 135 } 136