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 storage::CopyOrMoveFileValidator::ResultCallback& callback) 55 : data_(data.Pass()), callback_(callback) { 56 DCHECK(data_); 57 } 58 59 const std::string& data() { 60 return *data_; 61 } 62 63 // ImageDecoder::Delegate methods. 64 virtual void OnImageDecoded(const ImageDecoder* /*decoder*/, 65 const SkBitmap& /*decoded_image*/) OVERRIDE { 66 callback_.Run(base::File::FILE_OK); 67 delete this; 68 } 69 70 virtual void OnDecodeImageFailed(const ImageDecoder* /*decoder*/) OVERRIDE { 71 callback_.Run(base::File::FILE_ERROR_SECURITY); 72 delete this; 73 } 74 75 private: 76 scoped_ptr<std::string> data_; 77 storage::CopyOrMoveFileValidator::ResultCallback callback_; 78 79 DISALLOW_COPY_AND_ASSIGN(ImageDecoderDelegateAdapter); 80 }; 81 82 } // namespace 83 84 SupportedImageTypeValidator::~SupportedImageTypeValidator() {} 85 86 // static 87 bool SupportedImageTypeValidator::SupportsFileType(const base::FilePath& path) { 88 base::FilePath::StringType extension = path.Extension(); 89 return extension == FILE_PATH_LITERAL(".bmp") || 90 extension == FILE_PATH_LITERAL(".gif") || 91 extension == FILE_PATH_LITERAL(".jfif") || 92 extension == FILE_PATH_LITERAL(".jpeg") || 93 extension == FILE_PATH_LITERAL(".jpg") || 94 extension == FILE_PATH_LITERAL(".pjp") || 95 extension == FILE_PATH_LITERAL(".pjpeg") || 96 extension == FILE_PATH_LITERAL(".png") || 97 extension == FILE_PATH_LITERAL(".webp"); 98 } 99 100 void SupportedImageTypeValidator::StartPreWriteValidation( 101 const ResultCallback& result_callback) { 102 DCHECK_CURRENTLY_ON(BrowserThread::IO); 103 DCHECK(callback_.is_null()); 104 callback_ = result_callback; 105 106 BrowserThread::PostTaskAndReplyWithResult( 107 BrowserThread::FILE, 108 FROM_HERE, 109 base::Bind(&ReadOnFileThread, path_), 110 base::Bind(&SupportedImageTypeValidator::OnFileOpen, 111 weak_factory_.GetWeakPtr())); 112 } 113 114 SupportedImageTypeValidator::SupportedImageTypeValidator( 115 const base::FilePath& path) 116 : path_(path), 117 weak_factory_(this) { 118 } 119 120 void SupportedImageTypeValidator::OnFileOpen(scoped_ptr<std::string> data) { 121 DCHECK_CURRENTLY_ON(BrowserThread::IO); 122 if (!data.get()) { 123 callback_.Run(base::File::FILE_ERROR_SECURITY); 124 return; 125 } 126 127 // |adapter| will delete itself after a completion message is received. 128 ImageDecoderDelegateAdapter* adapter = 129 new ImageDecoderDelegateAdapter(data.Pass(), callback_); 130 decoder_ = new ImageDecoder(adapter, adapter->data(), 131 ImageDecoder::DEFAULT_CODEC); 132 decoder_->Start(content::BrowserThread::GetMessageLoopProxyForThread( 133 BrowserThread::IO)); 134 } 135